Dispute on basic use of unit test

introduce

Common unit tests are test methods and API s. Let's demonstrate the simple use of Xunit test framework. Some are unit tests written for demonstration.

There is a reversal at the bottom. Be sure to see the last

operation

Create a unit test project

This article also operates on the basis of the original project. Right click the solution to add a unit test project

 

The selected Framework version is. Net 5.0

Unit test project creation completed. Then reference our package

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>.NETCoreApp,Version=v5.0</TargetFramework>

    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.10" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
    <PackageReference Include="xunit" Version="2.4.1" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="coverlet.collector" Version="3.0.2" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\Net5ByDocker\Net5ByDocker.csproj" />
  </ItemGroup>

</Project>

TargetFramework: Specifies the target framework for the test project

IsPackable: sets whether unit test projects are allowed to be packaged

XUnit: the xUnit package introduces three sub packages, including the functions most developers want: (xunit.core test framework itself), xunit.assert (library containing Assert classes), and xunit.analyzers (common problems that enable Roslyn analyzer to detect unit testing and xUnit.net scalability)

Packages xunit.runner.Visual Studio and Microsoft.NET.Test.Sdk are capable of running test projects in Visual Studio and using dotnet test

coverlet.collector: This coverlet.collector package allows you to collect code coverage. If you do not intend to collect code coverage, you should remove this package reference.

If you want to use the MSTest framework, you just need to right-click the method to be tested to create a unit test

 

Click OK to create a unit test application for us. We will write about the unit test of the User controller in this

We do not use MSTest for testing here.

Create base class file BaseTest

public class BaseTest
{
    protected readonly ITestOutputHelper Output;
    public BaseTest(ITestOutputHelper output)
    {
        Output = output;
    }

    public string SerializeObject(object obj)
    {
        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            Formatting = Formatting.Indented,
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
        return JsonConvert.SerializeObject(obj, settings);
    }
}

/// <summary>
///   Build webhost
/// </summary>
public class BaseWebHostTest : BaseTest
{
    protected readonly TestServer Server;
    public BaseWebHostTest(ITestOutputHelper helper) : base(helper)
    {
        var service = Host.CreateDefaultBuilder()
                            .ConfigureWebHostDefaults(webBuilder =>
                            {
                                webBuilder.UseStartup<Startup>();
                            }).Build().Services;
        Server = new TestServer(service);
    }
}

/// <summary>
///   Just test the controller Api
/// </summary>
public class BaseHostTest : BaseTest
{
    protected readonly TestServer Server;
    public BaseHostTest(ITestOutputHelper helper) : base(helper)
    {
        Server = new TestServer(WebHost.CreateDefaultBuilder()
                .UseEnvironment("Development")//Test use
                .UseStartup<Startup>());
    }
}

Test API

Taking the demonstration of obtaining user information as an example, we test whether the status code returned after calling the interface is 200

Write constructor and assign HttpClient

public UserControllerTests(ITestOutputHelper helper) : base(helper)
{
    Client = Server.CreateClient();

    //var   token  =  "";  //  You can perform some custom request header operations on HttpClient
    //Client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
}

public HttpClient Client { get; }

test

[Fact()]
public async Task Get_User_ReturnOk()
{
    //Arrange    Assignment area
            
    //Act
    var response = await Client.GetAsync("api/user/getlist");

    //Assert
    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

    Output.WriteLine(await response.Content.ReadAsStringAsync());
}

There are generally three steps to write a unit test: array, Act, and Assert.

  • Arrange   It is the preparation stage, which is the preparation work, such as simulation data, initialization object, etc;

  • Act   It is the behavior phase, which uses the prepared data to call the method to be tested;

  • Assert   The assertion phase is to compare the returned value of the calling target method with the expected value. If it is consistent with the expectation, the test passes, otherwise it fails.

Right click the method name to run the test or debug the test

test method

For example, we unit test GetListAsync in IUserService, inherit from public classes, and obtain IUserService services through dependency injection

public class UserServiceTest : BaseWebHostTest
{
    private readonly IUserService _userService;

    public UserServiceTest(ITestOutputHelper helper) : base(helper)
    {
        _userService = Server.Services.GetRequiredService<IUserService>();
    }

    [Fact]
    public async Task GetUser_ReturnOk()
    {
        //Arrange ment: preparation stage  

        //Act: behavioral phase
        var response = await _userService.GetListAsync();

        //Assert: assert phase
        Assert.NotNull(response);
        Output.WriteLine(JsonConvert.SerializeObject(response));
    }
}

Right click the method name to run the test or debug the test

Unit test successful

Running tests in parallel

Running tests in parallel is supported after version 2.x of Xunit. In this way, you can make better use of server performance than before.

Create a new test class, RunnerTimeTest,

public class RunnerTimeTest
{
    [Fact]
    public void Test1()
    {
        Thread.Sleep(2000);
    }

    [Fact]
    public void Test2()
    {
        Thread.Sleep(3000);
    }
}

Let's guess how much time it takes to run the test class? 2s? 3s?

From this result, we can conclude that a test class is not executed in parallel. By default, each test class is a unique test set, and the tests of the same test class will not run in parallel with each other. Then we put the two test methods into different test classes

public class RunnerTimeTest
{
    [Fact]
    public void Test1()
    {
        Thread.Sleep(2000);
    }
}

public class RunnerTimeTest2
{
    [Fact]
    public void Test2()
    {
        Thread.Sleep(3000);
    }
}

Run to see the effect

We can get that different test classes are executed in parallel.

criticism

This is what I understand unit testing looks like, but after severe criticism from my colleagues, I know that we should use the single variable principle to control one difference and keep other variables the same, rather than uncontrollable dependencies like this article.

data

To create a unit test project from the command line: https://xunit.net/docs/getting-started/netcore/cmdline

ASP.NET Core unit test: https://www.cnblogs.com/willick/p/aspnetcore-unit-tests-with-xunit.html

Run tests in parallel: https://xunit.net/docs/running-tests-in-parallel

Tags: unit testing

Posted on Thu, 23 Sep 2021 05:49:19 -0400 by benrussell