Skip to content

Testing

Arsenty Politov edited this page Mar 15, 2019 · 1 revision

Testing utilities

Contains various extensions and mocks that can be used to emulate application environment in unit tests.

Related packages

  • DevGuild.AspNetCore.Testing
  • DevGuild.AspNetCore.Testing.Data
  • DevGuild.AspNetCore.Testing.Hosting
  • DevGuild.AspNetCore.Testing.Identity
  • DevGuild.AspNetCore.Testing.Mvc
  • DevGuild.AspNetCore.Testing.Storage

Configuration

  1. Install necessary packages into test project (they shouldn't be present in main project).
  2. Add class TestEnvironmentConfiguration that implements interface IMockConfiguration provided by one of the packages.
  3. Build an in-memory configuration, that can be used to configure services by adding method like this:
public virtual IConfiguration BuildConfiguration()
{
    var configurationData = new Dictionary<String, String>
    {
        { "ConnectionStrings:DefaultConnection", $"InMemory-{Guid.NewGuid():D}" },
        { "Bundling:Enabled", "false" },
        { "Storage:Images:Type", "InMemory" },
        { "Storage:Images:BaseUrl", "/images" },
        { "Storage:Files:Type", "InMemory" },
        { "Storage:Files:BaseUrl", "/files" },
        { "Mail:System:Type", "None" },
        { "Mail:System:Sender", "[email protected]" },
        { "Mail:System:BlindCopy", "[email protected]" },
        { "Mail:System:DebugMode", "true" },
        { "Sms:System:Type", "None" },
        { "Sms:System:SenderName", "DevGuild" }
    };

    var configurationBuilder = new ConfigurationBuilder();
    configurationBuilder.AddInMemoryCollection(configurationData);
    return configurationBuilder.Build();
}
  1. Implement required method ConfigureServices to mirror ConfigureServices from Startup class of main project.
    1. Some services can be skipped.
    2. Mock IHostingEnvironment by using services.MockHostingEnvironment extension:
    3. Instead of all storage providers, use AddInMemoryProvider to register InMemory provider.
    4. Instead of Sql Server or another database, use UseInMemoryDatabase to register InMemory database.
    5. Instead of using AddStateServices* extension to add identity services, use MockStateServices*.
    6. Don't use any live Email or SMS providers. Built-in None provider should be enough for testing.
    7. Use MockUrlHelper to register IUrlHelper service mock.
    8. Most of the domain services can be left as is.
  2. Add TestEnvironment class that inherits from MockEnvironmentBase with following code:
public class TestEnvironment : MockEnvironmentBase
{
    public static IMockEnvironment Create()
    {
        return MockEnvironment.Create<TestEnvironment>(new TestEnvironmentConfiguration());
    }
}

Testing

Set-up phase

  1. Create a testing environment by using TestEnvironment.Create method.
  2. Store created environment in test class instance field.
  3. If necessary - seed the data required for testing using environment.SeedAsync extension.

Example

private IMockEnvironment environment;

[SetUp]
public async Task Setup()
{
    this.environment = TestEnvironment.Create();
    await this.environment.SeedAsync(async seeder =>
    {
        await seeder.SeedRolesAsync<DbContext, Role, Guid>("Administrator");
    });
}

Testing phase

  1. If necessary - seed the data required for a specific test using environment.SeedAsync extension.
  2. Use environment.BeginRequest method to initialize request scope.
    1. Wrap it in using statement to automatically dispose request scope.
  3. Perform the testing.
    1. Use request.SignInAsync extension to emulate sign in as specific user (user needs to be seeded beforehand).
    2. Use request.GetService method to get registered service.
    3. Use request.CreateInstanceOf method to create a new instance of specified class with necessary dependencies injected (can be used to create controller instances).

Example

[Test]
public async Task HomeIndex()
{
    await this.environment.SeedAsync(async seeder =>
    {
        await seeder.SeedUserAsync<DbContext, ApplicationUser, Role, Guid>("admin", null, "Password123!", "Administrator");
    });
    using (var request = this.environment.BeginRequest())
    {
        await request.SignInAsync("admin");
        var controller = request.CreateInstanceOf<HomeController>();
        var result = await controller.Index();

        Assert.That(result, Is.InstanceOf<ViewResult>());
    }
}

Teardown phase

  1. Dispose instance of testing environment.

Example

[TearDown]
public void TearDown()
{
    this.environment.Dispose();
}
Clone this wiki locally