调用.NetCore API的.Netcore Controller的单元测试用例

时间:2018-06-08 22:57:00

标签: c# asp.net-core-mvc moq asp.net-core-2.0 xunit.net

我想写一个.net核心MVC控制器的单元测试用例。 Controller调用.net核心API。

我能够模拟IHttpHelper,但它总是返回null。 我有我的IHttpHelper

signal1.await();

我的Web API代码是

public interface IHttpHelper
{
    Task<HttpResponseMessage> GetAsync(string apiUrl);

    Task<HttpResponseMessage> PutAsync(string apiUrl, HttpContent content);

    Task<HttpResponseMessage> PostAsync(string apiUrl, HttpContent content);

    Task<HttpResponseMessage> DeleteAsync(string apiUrl);
}

我通过我的MVC控制器调用API以上

public class ClientTransferController : Controller
{
    private readonly CTUClientTransferProxy _searchProxy;

    private readonly IClientBLL _clientBll;

    public ClientTransferController(IConfiguration configuration) : this(configuration, new ClientBLL(configuration), new WcfServiceHelper())
    {
        _searchProxy = new CTUClientTransferProxy(configuration, new WcfServiceHelper());
    }


    public ClientTransferController(IConfiguration configuration, IClientBLL clientBll, IWcfServiceHelper wcfServiceHelper)
    {
        _clientBll = clientBll;
    }

    [Route("api/wcfctu/validatesitecodes")]
    public async Task<clsCTUValidateSiteCodesResults> ValidateSiteCodes([FromForm]string sourceSiteCode, [FromForm]string targetSiteCode)
    {
        var result = await _searchProxy.ValidateSiteCodesAsync(new clsCTUValidateSiteCodesCriteria { SourceSiteCode = sourceSiteCode, TargetSiteCode = targetSiteCode });
        return result;
    }
}

我想为public class FirmAdminController : Controller { private readonly IHttpHelper _httpHelper; public FirmAdminController(IHttpHelper httpHelper) { _httpHelper = httpHelper; } public async Task<IActionResult> ValidateSiteCodes(SiteCodeInputsViewModel siteCodeInputs) { if (ModelState.IsValid) { var values = new Dictionary<string, string> { {"sourceSiteCode", siteCodeInputs.SourceSiteCode.Sitecode}, {"targetSiteCode", siteCodeInputs.TargetSiteCode.Sitecode} }; var content = new FormUrlEncodedContent(values); var clientTransferValoidateSiteCodesApiUrl = $"api/wcfctu/validatesitecodes"; HttpResponseMessage response = await _httpHelper.PostAsync(clientTransferValoidateSiteCodesApiUrl, content); if (response.IsSuccessStatusCode) { var jsonData = response.Content.ReadAsStringAsync().Result; return Ok(jsonData); } } return Json(null); } } 的{​​{1}}编写单元测试用例。

以下是我的测试用例

ValidateSiteCodes

但是

ClientTransferController

不会返回public class FirmAdminControllerTests { private FirmAdminController _controller; private readonly Mock<IHttpHelper> _mockHttpHelper; public FirmAdminControllerTests() { _mockHttpHelper = new Mock<IHttpHelper>(); _controller = new FirmAdminController(_mockHttpHelper.Object); } [Fact] public void ValidateSiteCodes_IfValid() { //Arrange var clientTransferValoidateSiteCodesApiUrl = "api/wcfctu/validatesitecodes"; SiteCodeInputsViewModel siteCodeInputsViewModel = new SiteCodeInputsViewModel { SourceSiteCode = new SiteCodeInput { Sitecode = "Bravouat" }, TargetSiteCode = new SiteCodeInput { Sitecode = "CUAT" } }; var values = new Dictionary<string, string> { {"sourceSiteCode", siteCodeInputsViewModel.SourceSiteCode.Sitecode}, {"targetSiteCode", siteCodeInputsViewModel.TargetSiteCode.Sitecode} }; clsCTUValidateSiteCodesResults result1 = new clsCTUValidateSiteCodesResults { Success = true }; var headerDictionary = new HeaderDictionary(); var response = new Mock<HttpResponse>(); response.SetupGet(r => r.Headers).Returns(headerDictionary); var httpContext = new Mock<HttpContext>(); httpContext.SetupGet(a => a.Response).Returns(response.Object); var myContent = JsonConvert.SerializeObject(result1); var buffer = System.Text.Encoding.UTF8.GetBytes(myContent); var byteContent = new ByteArrayContent(buffer); byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); HttpResponseMessage responseMessage = new HttpResponseMessage { Content = byteContent, StatusCode = HttpStatusCode.OK }; var content = new FormUrlEncodedContent(values); _mockHttpHelper.Setup(c => c.PostAsync(clientTransferValoidateSiteCodesApiUrl, content)) .Returns(async () => { await Task.Yield(); return responseMessage; }); //Act var result = _controller.ValidateSiteCodes(siteCodeInputsViewModel); // Assert var viewResult = Assert.IsType<ViewResult>(result); } } 。它返回_mockHttpHelper.Setup(c => c.PostAsync(clientTransferValoidateSiteCodesApiUrl, content)) .Returns(async () => { await Task.Yield(); return responseMessage; }); ,这就是我的测试用例失败的原因。

1 个答案:

答案 0 :(得分:2)

测试失败有很多原因。

正在测试的控制器是混合异步和阻塞调用,如"Installed"

.Result

可能会导致死锁

参考Async/Await - Best Practices in Asynchronous Programming

该操作应始终保持异步

var jsonData = response.Content.ReadAsStringAsync().Result;

现在进行测试。后期设置过于复杂,包含预期的参数和返回响应的方式。

Moq有public async Task<IActionResult> ValidateSiteCodes(SiteCodeInputsViewModel siteCodeInputs) { if (ModelState.IsValid) { var values = new Dictionary<string, string> { {"sourceSiteCode", siteCodeInputs.SourceSiteCode.Sitecode}, {"targetSiteCode", siteCodeInputs.TargetSiteCode.Sitecode} }; var content = new FormUrlEncodedContent(values); var clientTransferValoidateSiteCodesApiUrl = $"api/wcfctu/validatesitecodes"; HttpResponseMessage response = await _httpHelper.PostAsync(clientTransferValoidateSiteCodesApiUrl, content); if (response.IsSuccessStatusCode) { var jsonData = await response.Content.ReadAsStringAsync(); return Ok(jsonData); } } return BadRequest(ModelState); } 允许模拟的异步流程按预期完成。

ReturnsAsync

为了保持这种异步,测试方法也应该是异步的。

_mockHttpHelper
    .Setup(_ => _.PostAsync(It.IsAny<string>(), It.IsAny<HttpContent>()))
    .ReturnsAsync(responseMessage);

并且等待正在测试的方法。

[Fact]
public async Task ValidateSiteCodes_IfValid() {
    //...
}