DEV Community

Alex
Alex

Posted on

.NET Learning Notes: Test Controller(using MVC.Testing and WireMock)

Controller Method Testing in MVC.Testing (xUnit)

1.Configuration Load Fails
Configuration files like secrets.json only load in the Development environment.
Make sure the environment is set to "Development" during testing if required secrets are needed.

2.Logging Output Not Visible
xUnit captures console output, so Console.WriteLine won't appear in test results by default.
Use ITestOutputHelper instead. Inject it via the test class constructor like this:

   public class MyTests
   {
       private readonly ITestOutputHelper _output;

       public MyTests(ITestOutputHelper output)
       {
           _output = output;
       }
   }
Enter fullscreen mode Exit fullscreen mode

3.Adding Authorization Token to Test Requests
If your API requires a Bearer token, set it on the HttpClient before sending requests:

   _client.DefaultRequestHeaders.Authorization = 
       new AuthenticationHeaderValue("Bearer", token.TokenStr);
Enter fullscreen mode Exit fullscreen mode
// Example:
public class TaskControllerTests : IClassFixture<TestingWebApplicationFactory<Program>>
{
    private readonly HttpClient _client;
    private readonly ITokenHelper _tokenHelper;
    private readonly IConfiguration _configuration;
    private readonly ITestOutputHelper _output;

    public TaskControllerTests(TestingWebApplicationFactory<Program> factory, ITestOutputHelper output)
    {
        _client = factory.CreateClient();
        _tokenHelper = factory.Services.GetRequiredService<ITokenHelper>();
        _configuration = factory.Services.GetRequiredService<IConfiguration>();
        _output = output;
    }

    [Fact]
    public async Task CreateTaskAsync_ShouldReturnSuccess()
    {
        // Arrange: JSON request matching CreateTaskRequest shape
        var testUserId = "7";
        var entry = new
        {
            UserId = testUserId,
            JWTVersion = 1,
        };
        var token = _tokenHelper.CreateToken(entry, TokenType.AccessToken);
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.TokenStr);
        string UUID = Guid.NewGuid().ToString();
        var request = new CreateTaskRequest("Test Task" + UUID, "Test Description" + UUID, 
            DateTime.Today.AddDays(1), 1, "3");
        // Act: Call your API route (adjust route prefix if needed)
        var response = await _client.PostAsJsonAsync("/Task/CreateTask", request);

        // Assert: success status and response content
        response.EnsureSuccessStatusCode();

        var responseString = await response.Content.ReadAsStringAsync();
        var apiResponse = JsonSerializer.Deserialize<ApiResponse<DataWrapper<string>>>(responseString);
        apiResponse.Should().NotBeNull();
        apiResponse.data.info.Should().BeEquivalentTo("Task created successfully");
        apiResponse.data.code.Should().Be(300000);
    }
}

public class TestingWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.UseEnvironment("Testing"); // 设置环境名,方便读取 appsettings.Testing.json
    }
}

public class ApiResponse<T>
{
    public int code { get; set; }
    public string message { get; set; }
    public T data { get; set; }
}

public class DataWrapper<T>
{
    public int code { get; set; }
    public T info { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

What Is WireMock.Net?

WireMock.Net is a tool which mimics the behaviour of an HTTP API, it captures the HTTP requests and sends it to WireMock.Net HTTP server, which is started and as a result, we can setup expectations, call the service and then verify its behaviour.

When Should We Use WireMock.Net?

  1. HTTP Dependencies Not Ready
  2. Unit Test classes which use HTTP APIs
  3. Integration or End-to-end tests using external HTTP APIs

Install:

dotnet add package WireMock.Net.StandAlone
dotnet add package WireMock.Net
Enter fullscreen mode Exit fullscreen mode


//Example:
using System.Net.Http;
using System.Threading.Tasks;
using WireMock.Server;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using Xunit;

public class WeatherServiceTests
{
    [Fact]
    public async Task GetWeather_ShouldReturnMockedData()
    {
        // 启动 WireMock 服务器
        var server = WireMockServer.Start();

        // 配置模拟响应
        server.Given(
            Request.Create().WithPath("/weather").UsingGet().WithParam("city", "London")
        )
        .RespondWith(
            Response.Create()
                .WithStatusCode(200)
                .WithHeader("Content-Type", "application/json")
                .WithBody("{ \"city\": \"London\", \"temperature\": 20 }")
        );

        // 使用 HttpClient 发出请求(请求 WireMock 模拟服务)
        var client = new HttpClient();
        var response = await client.GetAsync($"{server.Urls[0]}/weather?city=London");
        var content = await response.Content.ReadAsStringAsync();

        // 验证返回内容
        Assert.Contains("\"temperature\": 20", content);

        server.Stop();
    }
}
//
Enter fullscreen mode Exit fullscreen mode

Top comments (0)