簡體   English   中英

測試具有外部依賴項的操作方法

[英]Testing an action method with external dependencies

這是HomeController中的Action方法的示例:

[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; }
}

不幸的是,上述方法不起作用。 由於我很困惑,您能給我以下答案嗎?

  • 測試UnitTest操作的最佳方法是什么? 我的方法錯了嗎? 我是否只需要從JsonRightTest方法調用API而不涉及操作
  • 實際上,在這種情況下,我們是否有unit測試或integrated測試?

我想稱呼實際的外部終點。

該API( https://jsonplaceholder.typicode.com/posts )可在Internet上找到,並可用於測試目的。

這似乎是一個XY問題和各種顧慮。

被測試的代碼與實現問題緊密相關,並且應該將外部調用封裝在服務抽象之后,該服務抽象可以在隔離的單元測試中進行模擬。

應該遵循的一些重構步驟。

測試中正在構建的那些模型應該起作用。

[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>();

以便將其正確注入到從屬控制器中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM