亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

.NET MVC 中帶有 HttpClient 的單元測試控制器

.NET MVC 中帶有 HttpClient 的單元測試控制器

C#
慕容3067478 2021-11-14 17:13:21
所以我有一個使用 HttpClient 來調用 web 服務的控制器,如下所示:public class DemoController : Controller{    HttpClient client;    string baseUrl = "http://localhost:90/webservice";    public DemoController()    {        client = new HttpClient        {            BaseAddress = new Uri(baseUrl)        };    }    // GET: DemoInfo    public async Task<ActionResult> Index()    {        HttpResponseMessage response = await client.GetAsync(baseUrl + "vehicle/menu/year");        string content = "";        MenuItems result = null;        if (response.IsSuccessStatusCode)        {            content = await response.Content.ReadAsStringAsync();            result = (MenuItems)new XmlSerializer(typeof(MenuItems)).Deserialize(new StringReader(content));        }        return View("Index", result);    }}我對這個動作的單元測試如下:    [TestMethod]    public async Task Test_Index()    {        // Arrange        DemoController controller = new DemoController();        // Act        var result = await controller.Index();        ViewResult viewResult = (ViewResult) result;        // Assert        Assert.AreEqual("Index", viewResult.ViewName);        Assert.IsNotNull(viewResult.Model);    }所以很明顯,我想避免每次運行測試時都調用 Web 服務。我是否會選擇像 Unity 這樣的 IoC 容器,以便將 HttpClient 注入控制器中?對于我想要實現的目標來說,這是否太過分了?我知道有很多歷史,人們通過這個github issue在單元測試中努力正確模擬 httpclient 。如果您能深入了解如何編寫控制器以在仍可測試的情況下進行服務調用,我們將不勝感激。
查看完整描述

2 回答

?
慕工程0101907

TA貢獻1887條經驗 獲得超5個贊

所有使測試變慢的依賴項都應該被抽象出來。用抽象

包裹HttpClient起來,您可以在測試中模擬它。


public interface IMyClient

{

    Task<string> GetRawDataFrom(string url);

}

那么你的控制器將依賴于那個抽象


public class DemoController : Controller

{

    private readonly IMyClient _client;

    private string _baseUrl = "http://localhost:90/webservice";


    public DemoController(IMyClient client)

    {

        _client = client;

    }


    public async Task<ActionResult> Index()

    {

        var rawData = _client.GetRawDataFrom($"{_baseUrl}vehicle/menu/year");

        using (var reader = new StringReader(rawData))

        {

            var result = 

                (MenuItems)new XmlSerializer(typeof(MenuItems)).Deserialize(reader);

            return View("Index", result);

        }

    }

}

然后在測試中,您可以模擬您的抽象以返回預期數據


public class FakeClient : IMyClient

{

     public string RawData { get; set; }


     public Task<string> GetRawDataFrom(string url)

     {

         return Task.FromResult(RawData);

     }

}


[TestMethod]

public async Task Test_Index()

{

    // Arrange

    var fakeClient = new FakeClient 

    { 

        RawData = @"[ 

            { Name: "One", Path: "/one" },

            { Name: "Two", Path: "/two" }  

        ]" 

    };       

    DemoController controller = new DemoController(fakeClient);


    // Act

    var result = await controller.Index();

    ViewResult viewResult = (ViewResult)result;


    // Assert

    Assert.AreEqual("Index", viewResult.ViewName);

    Assert.IsNotNull(viewResult.Model);

}

實際實施將使用 HttpClient


public class MyHttpClient : IMyClient

     public Task<string> GetRawDataFrom(string url)

     {

         var response = await client.GetAsync(url);

         if (response.IsSuccessStatusCode)

         {

             return await response.Content.ReadAsStringAsync();

         }

     }

}


查看完整回答
反對 回復 2021-11-14
?
BIG陽

TA貢獻1859條經驗 獲得超6個贊

在HttpClient沒有服務包裝器、模擬或 IoC 容器的情況下測試調用的另一種方法是使用Flurl,這是一個小型包裝器庫HttpClient,提供(除其他外)一些強大的測試功能。[免責聲明:我是作者]


這是您的控制器的外觀。有幾種方法可以做到這一點,但這種方法使用字符串擴展方法來完全抽象出客戶端。(HttpClient為您管理每個主機的單個實例以防止出現問題。)


using Flurl.Http;


public class DemoController : Controller

{

    string baseUrl = "http://localhost:90/webservice";


    // GET: DemoInfo

    public async Task<ActionResult> Index()

    {

        var content = await baseUrl

            .AppendPathSegment("vehicle/menu/year")

            .GetStringAsync();


        var result = (MenuItems)new XmlSerializer(typeof(MenuItems)).Deserialize(new StringReader(content));

        return View("Index", result);

    }

}

和測試:


using Flurl.Http;


[TestMethod]

public async Task Test_Index()

{

    // fake & record all HTTP calls in the test subject

    using (var httpTest = new HttpTest())

    {

        // Arrange

        httpTest.RespondWith(200, "<xml>some fake response xml...</xml>");

        DemoController controller = new DemoController();


        // Act

        var result = await controller.Index();

        ViewResult viewResult = (ViewResult) result;


        // Assert

        Assert.AreEqual("Index", viewResult.ViewName);

        Assert.IsNotNull(viewResult.Model);

    }

}

Flurl.Http 在NuGet上可用。


查看完整回答
反對 回復 2021-11-14
  • 2 回答
  • 0 關注
  • 221 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號