統合テストを通してエンドポイントを呼び出す方法


それは素晴らしいときにすべてのユニットテストの緑の看板をどこに戻っている.それでも、プロジェクトを実行すると、インフラ設定が間違っているため、エラーが発生しますWeb API 適切に😑. それはあなたのログ、データベース、プロバイダ、よく、他の多くのものを設定する方法です.それを修正するか、その影響を最小にする1つのアプローチは、統合テストを通してあります.それで、どのように、あなたはそれのために速いセットアップをすることができますか🤔? ところで、このブログ記事では、次のような技術を検討します.
  • .NET Core 5
  • xUnit.net
  • Moq
  • サンプルプロジェクトの説明


    以下はサンプルフローを示すイメージです.

    3つのステップから構成されます.
  • ユーザーはエンドポイント/API/V 1/ムービーを呼び出します.
  • アプリケーションは偽の処理を行います.
  • ランダムなムービーは、ユーザーに返されます.
  • このビジネスルールを管理するには、以下のコントローラを使います.
    [ApiController]
    [Route("api/v1/[controller]")]
    public class MoviesController : ControllerBase
    {
        private readonly IFilmSpecialist _filmSpecialist;
    
        public MoviesController(IFilmSpecialist filmSpecialist)
        {
            _filmSpecialist = filmSpecialist;
        }
    
        [HttpGet]
        public Movie Get()
        {
            Log.Information("Let me ask the film specialist...");
            var movie = _filmSpecialist.SuggestSomeMovie();
            Log.Information("Suggested movie: {Movie}", movie);
            return movie;
        }
    }
    
    誰が偽の処理を行う責任があります.
    public class FilmSpecialist : IFilmSpecialist
    {
        private static readonly Movie[] Films =
        {
            new("RoboCop", "10/08/1987", new[] {"Action", "Thriller", "Science Fiction"}, "1h 42m"),
            new("The Matrix", "05/21/1999", new[] {"Action", "Science Fiction"}, "2h 16m"),
            new("Soul", "12/25/2020", new[] {"Family", "Animation", "Comedy", "Drama", "Music", "Fantasy"}, "1h 41m"),
            new("Space Jam", "12/25/1996", new[] {"Adventure", "Animation", "Comedy", "Family"}, "1h 28m"),
            new("Aladdin", "07/03/1993", new[] {"Animation", "Family", "Adventure", "Fantasy", "Romance"}, "1h 28m"),
            new("The World of Dragon Ball Z", "01/21/2000", new[] {"Action"}, "20m"),
        };
    
        public Movie SuggestSomeMovie()
        {
            Log.Debug("OKAY! Which film will I suggest 🤔");
            Random random = new();
            var filmIndexThatIWillSuggest = random.Next(0, Films.Length);
            Log.Information("Will suggest the film with index {FilmIndex}!", filmIndexThatIWillSuggest);
    
            return Films[filmIndexThatIWillSuggest];
        }
    }
    
    最初に、我々のメソッド契約が尊重されていることを保証するために、単位テストをしましょう.

    単体テストからの起動


    ここでは、ランダムなムービーを返すサービスに関する単純な単体テストを行います.次のように書くことができます.
    public class FilmSpecialistTests
    {
        private readonly IFilmSpecialist _filmSpecialist = new FilmSpecialist();
    
        [Fact]
        public void ShouldReturnRandomMovieWhenAsked()
        {
            // Act
            var suggestedMovie = _filmSpecialist.SuggestSomeMovie();
            // Assert
            var expectedTiles = new[]
            {
                "RoboCop", "The Matrix", "Soul", "Space Jam", "Aladdin", "The World of Dragon Ball Z"
            };
            suggestedMovie.Title.Should().BeOneOf(expectedTiles);
        }
    }
    

    APIへの実際のHTTPリクエストの作成


    エンドポイントをコールするには、class fixture …の助けを得てWebApplicationFactory より詳しい情報はsection Basic tests with the default WebApplicationFactory インIntegration tests in ASP.NET Core ガイド.クラスのテストコンストラクタでは、ファクトリを使用してHttpClientを作成することができます.また、注入されたサービスをモックと交換したいとしましょうConfigureTestServices . 完全な例を示します.
    public class MoviesControllerITests : IClassFixture<WebApplicationFactory<Startup>>
    {
        private readonly IFilmSpecialist _filmSpecialist;
        private HttpClient _httpClient;
    
        public MoviesControllerITests(WebApplicationFactory<Startup> factory)
        {
            _filmSpecialist = Mock.Of<IFilmSpecialist>();
            _httpClient = factory.WithWebHostBuilder(builder =>
            {
                // https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-5.0#inject-mock-services
                builder.ConfigureTestServices(services =>
                {
                    services.RemoveAll<IFilmSpecialist>();
                    services.TryAddTransient(_ => _filmSpecialist);
                });
            }).CreateClient();
        }
    
        [Fact]
        public async Task ShouldCreateGameGivenFirstMovementIsBeingExecuted()
        {
            // Arrange
            var requestPath = "/api/v1/movies";
            var movieToBeSuggested = new Movie("Schindler's List", "12/31/1993", new[] {"Drama", "History", "War"}, "3h 15m");
            Mock.Get(_filmSpecialist)
                .Setup(f => f.SuggestSomeMovie())
                .Returns(movieToBeSuggested)
                .Verifiable();
            // Act
            var response = await _httpClient.GetAsync(requestPath);
            response.StatusCode.Should().Be(HttpStatusCode.OK);
            var movie = await response.Content.ReadFromJsonAsync<Movie>();
            // Assert
            movie.Should().BeEquivalentTo(movieToBeSuggested);
            Mock.Get(_filmSpecialist).Verify();
        }
    }
    
    ところで、使用にWebApplicationFactory , パッケージをインストールする必要があります.
    Microsoft.AspNetCore.Mvc.Testing
    
    それはかなり簡単です🤗. 私はそれをそのまま残します、しかし、我々は我々の統合テストを抽象化することができました😏.

    物事を終わらせる


    私は、あなたが最初に言ったように、あなたのコードがインフラストラクチャ層で予想通りに出荷されることをほとんど保証することができるので、時々、安い統合テストをすることから大きな利益を得ることができると思います.この記事では、いくぶん単純な例をあげましたが、物事はより挑戦的でありえます、ブローカー接続に関しては😜.
    あなたは、私がここで示したコードに相談することができますthis GitHub repository . あなたはDockerを使用することができますrun the project だけでなくexecute its tests . チェックするREADME 詳細は
    聴聞会.