29

I'm using aspnetcore 3.0 preview 7 for my web api project. Currently I'm implementing the integration tests. (To make the tests easier first, I commented out the Authorize attribute on the controllers.)

The server responds "404 not found". I'm confused about not having "usemvc" in the startup anymore - should I do something different in setting up the test server now? Or does anybody have an idea what causes the 404? (The MS docs for integration testing with 3.0 are not updated yet). I also tried with preview 8, but same issue.

Test class:

   [OneTimeTearDown]
    public virtual void Cleanup()
    {
        _unAuthenticatedServer.Dispose();
    }

    [OneTimeSetUp]
    public virtual void Initialize()
    {
        _unAuthenticatedServer = CreateServer(null);
    }

    protected TestServer CreateServer(
        string currentDirectory = null)
    {
        IWebHostBuilder webHostBuilder = WebHost.CreateDefaultBuilder();

        webHostBuilder.UseContentRoot(currentDirectory == null
            ? Directory.GetCurrentDirectory()
            : Directory.GetCurrentDirectory() + $"\\{currentDirectory}");


        webHostBuilder.UseStartup<TestStartup>();
        webHostBuilder.UseEnvironment("Test");

        webHostBuilder.ConfigureAppConfiguration((_, config) => config.AddJsonFile("appsettings.Test.json"));

        return new TestServer(webHostBuilder);
    }

    [Test, Order(1)]
    public async Task Should_Get_Games_Return_StatusCode_Ok()
    {
        //Arrange
        IList<GameDto> expectedDtos = GameDtoTestData.Games;

        //Act
        HttpResponseMessage responseMessage = await _unAuthenticatedServer
            .CreateClient()
            .GetAsync("api/games");

        //Assert
        responseMessage.StatusCode.Should().Be(HttpStatusCode.OK); // but is: 404 NotFound

        var responseString = await responseMessage.Content.ReadAsStringAsync();
        IEnumerable<GameDto> result = JsonConvert.DeserializeObject<IEnumerable<GameDto>>(responseString);

        result.Should().BeEquivalentTo(expectedDtos);
    }

Controller:

[Route("api/[controller]")]
[ApiController]
public class GamesController : ControllerBase
{
    private readonly IGameService _gameService;

    public GamesController(IGameService gameService)
    {
        _gameService = gameService;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<GameDto>>> Get()
    {
        return Ok(await _gameService.GetAsync());
    }
}

Installed Nuget packages test project:

 <ItemGroup>
    <PackageReference Include="FluentAssertions" Version="5.8.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.0.0-preview7.19365.7" />
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.0.0-preview7.19365.7" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.2.6" />
    <PackageReference Include="nunit" Version="3.12.0" />
    <PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
  </ItemGroup>

Installed Nuget packages api project:

  <ItemGroup>
    <PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Version="3.0.0-preview6.19307.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.6" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.2.6">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>
MatterOfFact
  • 1,253
  • 2
  • 18
  • 49
  • Does this answer your question? [Why is TestServer not able to find controllers when controller is in separate assembly for asp.net core app?](https://stackoverflow.com/questions/43669633/why-is-testserver-not-able-to-find-controllers-when-controller-is-in-separate-as) – psfinaki Nov 11 '19 at 17:13

1 Answers1

57

What works for me is to register the assembly containing the Startup class as an Mvc Application Part.

In your startup class, add the following code to IServiceProvider ConfigureServices(IServiceCollection services):

services
  .AddMvc(...)
  .AddApplicationPart(typeof(Startup).Assembly)

It may seem a bit odd that you need to register the assembly containing the Startup class as an application part in the Startup class itself; but this approach did work for me.

Frederik Carlier
  • 4,606
  • 1
  • 25
  • 36
  • 1
    This works for me, thank you! Hoping that Microsoft will make this workaround obsolote in the future :-) – MatterOfFact Sep 24 '19 at 13:33
  • 10
    I found that this answer also had the same result but was much cleaner in my case during a .NET Core 2.2 to 3.0 migration https://stackoverflow.com/a/58946016/2831961 – daniel.caspers Nov 20 '19 at 03:31
  • 2
    Wow. This was a lifesaver. I scratched my head for an entire day before I stumpled upon this one. – Lost Mar 17 '20 at 19:49
  • Wow! That worked. Can't imagine how you figured that out, but thanks a lot!! – mike gold Jun 25 '20 at 19:32
  • Thank you sir! You saved me! :D – Cubelaster Jun 02 '21 at 13:23
  • Interesting . thanks . it's work for me . but I have a question. if we create web api project why we need to add mvc service to find controller for test ? – Iman Jun 06 '22 at 11:45
  • It seems like the default AddMvc(...) call uses the executing assembly as the default location to search for controllers. When running your tests, this is the test assembly, not your API assembly. Hence it doesn't find your controllers by default. – Rossco May 17 '23 at 02:23