1

I am developing a web API using ASP.Net core. I am doing integrated testing to my project. I am following this link, https://koukia.ca/integration-testing-in-asp-net-core-2-0-51d14ede3968. This is my code.

I have the controller to be tested in the thegoodyard.api project.

namespace thegoodyard.api.Controllers
{
   [Produces("application/json")]
   [Route("api/category")]
   public class CategoryController: Controller
   {
      [HttpGet("details/{id}")]
      public string GetCategory(int id = 0)
      {
         return "This is the message: " + id.ToString();
      }
   }
}

I added a new unit test project called thegoodyard.tests to the solution. I added a TestServerFixture class with the following definition

namespace thegoodyard.tests
{
    public class TestServerFixture : IDisposable
    {
      private readonly TestServer _testServer;
      public HttpClient Client { get; }

      public TestServerFixture()
      {
         var builder = new WebHostBuilder()
                .UseContentRoot(GetContentRootPath())
                .UseEnvironment("Development")
                .UseStartup<Startup>();  // Uses Start up class from your API Host project to configure the test server

         _testServer = new TestServer(builder);
         Client = _testServer.CreateClient();
      }

      private string GetContentRootPath()
      {
         var testProjectPath = PlatformServices.Default.Application.ApplicationBasePath;
         var relativePathToHostProject = @"..\..\..\..\..\..\thegoodyard.api";
         return Path.Combine(testProjectPath, relativePathToHostProject);
      }

      public void Dispose()
      {
         Client.Dispose();
         _testServer.Dispose();
      }
   }
}

Then again in the test project, I created a new class called, CategoryControllerTests with the following definition.

namespace thegoodyard.tests
{
    public class CategoryControllerTests: IClassFixture<TestServerFixture>
   {
      private readonly TestServerFixture _fixture;

      public CategoryControllerTests(TestServerFixture fixture)
      {
         _fixture = fixture;
      }

      [Fact]
      public async Task GetCategoryDetai()
      {
         var response = await _fixture.Client.GetAsync("api/category/details/3");

         response.EnsureSuccessStatusCode();

         var responseString = await response.Content.ReadAsStringAsync();

         bool containMessage = false; //responseString.Contains("This is the message: 3"); - I commented on purpose to make the test fails.
         Assert.True(containMessage);
      }
   }
}

Then I right on the test method and clicked run tests in the option to run the test. But none of the tests was run. This is the output. enter image description here

What is missing in my code? How can I get my integrated test running?

Community
  • 1
  • 1
Wai Yan Hein
  • 13,651
  • 35
  • 180
  • 372
  • Do you have Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" in your csproj file for tests project? Try to remove it. If doesn't help, check this https://stackoverflow.com/questions/35103781/why-is-the-visual-studio-2015-2017-test-runner-not-discovering-my-xunit-v2-tests/35103782 to make sure the problem is not covered yet. – Dmitry Pavlov Sep 17 '18 at 14:45

3 Answers3

1

Please check following NuGet packages in your project:

Microsoft.AspNetCore.TestHost
Microsoft.NET.Test.Sdk
xunit
xunit.runner.visualstudio
Artem Polishchuk
  • 505
  • 5
  • 17
0

Perhaps there's a build error that's preventing the project from being compiled. There's really not enough information here to say for sure. Rebuild your solution, and ensure there's no errors.

Aside from that, you can remove some variables by reducing the test code needed. ASP.NET Core includes a WebApplicationFactory<TEntryPoint> fixture out of the box for bootstrapping a test server. You can therefore change your test code to just:

public class CategoryControllerTests: IClassFixture<WebApplicationFactory<Startup>>
{
    private readonly WebApplicationFactory<Startup> _factory;

    public CategoryControllerTests(WebApplicationFactory<Startup> factory)
    {
        _factory = factory;
    }

    [Fact]
    public async Task GetCategoryDetail()
    {
        var client = _factory.CreateClient();
        var response = await client.GetAsync("api/category/details/3");
        ...

See the documentation for additional information and more advanced scenarios.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
0

This way works fine for xUnit based intergration tests, which use Startup configuration. the code blow also demonstrates how to override some settings in appSetting.json to specific values for testing, as well as how to access to DI services.

using System;
using System.Net.Http;
using MyNamespace.Web;
using MyNamespace.Services;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace MyNamespace.Tests
{
    public class TestServerDependent : IDisposable
    {
        private readonly TestServerFixture _fixture;
        public TestServer TestServer => _fixture.Server;
        public HttpClient Client => _fixture.Client;

        public TestServerDependent()
        {
            _fixture = new TestServerFixture();

            var myService = GetService<IMyService>();
            // myService.PerformAnyPreparationsForTests();
        }

        protected TService GetService<TService>()
            where TService : class
        {
            return _fixture.GetService<TService>();
        }

        public void Dispose()
        {
            _fixture?.Dispose();
        }
    }

    public class TestServerFixture : IDisposable
    {
        public TestServer Server { get; }
        public HttpClient Client { get; }

        public TestServerFixture()
        {
            var hostBuilder = WebHost.CreateDefaultBuilder()
                .ConfigureAppConfiguration(
                    (builderContext, config) =>
                    {
                        var env = builderContext.HostingEnvironment;
                        config
                            .AddJsonFile("appsettings.json", optional: false)
                            .AddJsonFile("appsettings.Testing.json", optional: false,
                                reloadOnChange: true);
                    })
                .ConfigureLogging(
                    (hostingContext, logging) =>
                    {
                        logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                        logging.AddConsole();
                        logging.AddDebug();
                    })
                .UseStartup<Startup>();

            Server = new TestServer(hostBuilder);
            Client = Server.CreateClient();
        }

        public void Dispose()
        {
            Server.Dispose();
            Client.Dispose();
        }

        public TService GetService<TService>()
            where TService : class
        {
            return Server?.Host?.Services?.GetService(typeof(TService)) as TService;
        }
    }
}

How the simple integration test might look like with the described above:

using System.Net;
using Xunit;

namespace MyNamespace.Tests
{
    public class SimpleIntegrationTest : TestServerDependent
    {
        [Fact]
        public void RedirectToLoginPage()
        {
            var httpResponseMessage = Client.GetAsync("/").Result;

            // Smoke test to make sure you are redirected (to Login page for instance)
            Assert.Equal(HttpStatusCode.Redirect, httpResponseMessage.StatusCode);
        }
    }
}
Dmitry Pavlov
  • 30,789
  • 8
  • 97
  • 121