使用外部依赖项测试操作方法

时间:2018-01-31 15:45:10

标签: c# unit-testing asp.net-core integration-testing

这是var pos = Player.getBoundingClientRect(); var BeginningPos = pos.x; 内的Action方法示例:

HomeController

我想测试一下,但我不知道怎么做。我尝试了以下方法:

[HttpPost]
public async Task<dynamic> UnitTest(string data)
{
    var httpClient = new HttpClient();
    var request = JsonConvert.SerializeObject(data);
    var url = "https://jsonplaceholder.typicode.com/posts";
    var response = await httpClient.PostAsync(url, new StringContent(request, Encoding.UTF8, "application/json"));
    string responseContent = await response.Content.ReadAsStringAsync();
    return responseContent;
}

不幸的是,上述方法无效。由于我很困惑,你可以给我一些以下答案:

  • 测试[TestMethod] public async Task JsonRightTest() { MyModelR model1 = new MyModelR { Title = "foo", Body = "bar", UserId = 1 }; string output1 = JsonConvert.SerializeObject(model1); var url = "Home/UnitTest"; var response = await _client.PostAsync(url, new StringContent(output1, Encoding.UTF8, "application/json")); response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync(); var responseModel = JsonConvert.DeserializeObject<MyModel>(responseContent); // Assert Assert.AreEqual(1, responseModel.UserId); } internal class MyModel { public string Title { get; set; } public string Body { get; set; } public int UserId { get; set; } public int Id { get; set; } } internal class MyModelR { public string Title { get; set; } public string Body { get; set; } public int UserId { get; set; } } 行动的最佳方法是什么?我的方法有误吗? 我是否只需要从JsonRightTest方法调用API而不涉及操作
  • 实际上,在这种情况下,我们是否进行了UnitTestunit测试?

我想调用实际的外部终点。

API(https://jsonplaceholder.typicode.com/posts)可在Internet上找到,可用于测试目的。

1 个答案:

答案 0 :(得分:2)

这似乎是一个XY problem和一系列问题。

正在测试的代码与实现问题紧密相关,应该将外部调用封装在服务抽象之后,可以在隔离的单元测试中进行模拟。

应该遵循的一些重构步骤......

在测试中构建的那些模型应该在行动中。

[HttpPost]
public async Task<IActionResult> UnitTest([FromBody]MyDataR data) {
    var httpClient = new HttpClient();
    var requestJson = JsonConvert.SerializeObject(data);
    var url = "https://jsonplaceholder.typicode.com/posts";
    var response = await httpClient.PostAsync(url, new StringContent(requestJson, Encoding.UTF8, "application/json"));
    if(response.IsSuccessStatusCode) {
        var responseContent = await response.Content.ReadAsStringAsync();
        var responseModel = JsonConvert.DeserializeObject<MyModel>(responseContent);        
        return Ok(responseModel);
    }else 
        return StatusCode(response.StatusCode);
}

进一步重构,应该抽象出外部端点的实际调用

public interface IExternalService {
    Task<MyModel> PostDataAsync(MyData data);
}

并相应地实施

public class ExternalService : IExternalService  {
    // should consider abstracting this as well but that is another matter
    static Lazy<HttpClient> _httpClient = new Lazy<HttpClient>(() => new HttpClient());

    private HttpClient httpClient {
        get { return _httpClient.Value; }
    }       

    public async Task<MyModel> PostDataAsync(MyData data) {
        var requestJson = JsonConvert.SerializeObject(data);
        var url = "https://jsonplaceholder.typicode.com/posts";
        var content = new StringContent(requestJson, Encoding.UTF8, "application/json")
        var response = await httpClient.PostAsync(url, content);
        var responseContent = await response.Content.ReadAsStringAsync();
        if(response.IsSuccessStatusCode) {
            var responseContent = await response.Content.ReadAsStringAsync();
            var responseModel = JsonConvert.DeserializeObject<MyModel>(responseContent);        
            return responseModel;
        }else 
            return null;
    }
}

控制器中的操作现在看起来像

private readonly IExternalService externalService; // Assumed injected into the controller

[HttpPost]
public async Task<IActionResult> UnitTest([FromBody]MyDataR data) {
    var responseModel = await externalService.PostDataAsync(data);
    if(responseModel != null) {
        return Ok(responseModel);
    }else 
        return BadRequest();
}

通过删除与外部服务调用的紧耦合,这将允许根据需要单独测试控制器,以验证其行为符合预期。

如果希望检查外部端点是否按预期运行,现在可以自行测试外部服务调用实现。由于它依赖于实际的外部端点,因此将被视为集成测试。

[TestMethod]
public async Task JsonRightTest() {
    // Arrange
    var expected = 1;

    var model = new MyModelR {
        Title = "foo",
        Body = "bar",
        UserId = 1
    };

    var target = new ExternalService(); // System under test

    // Act
    var responseModel = await target.PostDataAsync(model);

    // Assert
    Assert.IsNotNull(responseModel);
    var actual = responseModel.UserId;
    Assert.AreEqual(expected, actual);
}

现在应该可以更容易地检查外部服务,以验证它是否按预期运行。

在生产中,您将确保外部服务抽象及其实现在组合根中注册。

services.AddTransient<IExternalService, ExternalService>();

以便正确地将其注入从属控制器。