【问题标题】:WebAPI 2 Unit Test Error with method reference Service带有方法参考服务的 WebAPI 2 单元测试错误
【发布时间】:2017-11-08 22:41:39
【问题描述】:

我有一个 WebAPI2 项目,其中的控制器引用了一些其他服务,我知道一切正常,因为我已经发布了 webapi 并且可以正常工作,但是现在我想做一些单元测试。 在我最初的解决方案中,我创建了一个新的测试项目并创建了我的测试方法

[TestMethod]
    public void GetVerifyLogin_ShouldReturnUser() {
        UserAccountController controller = new UserAccountController();
        var result = controller.GetVerifyLogin("2171251", "2171251");
        Assert.IsNotNull(result);
    }

当我运行测试时,出现以下错误:

结果消息:测试方法 StagesApiMsaTest.UserAccountControllerTest.GetVerifyLogin_ShouldReturnUser 抛出异常:System.InvalidOperationException:找不到 引用合约的默认端点元素 ServiceModel 客户端中的“RapidFunctionsService.R_Service” 配置部分。这可能是因为没有配置文件 为您的应用程序找到,或者因为没有匹配的端点元素 该合同可以在客户端元素中找到。

我正在测试的方法有几行代码,但我将提取该方法:

 foreach (var siteItem in siteResult.ResultSet)
                    {
                        result.SiteNum = siteItem.SiteNum;
                        result.DevNum = siteItem.DevNum;
                        result.TrasmitterCode = siteItem.TransmitterCode;
                    }

                    RapidFunctionsService.R_ServiceClient service = new RapidFunctionsService.R_ServiceClient();
                    RapidFunctionsService.ZipCodeVerifyDealerResult xipResult = service.ZipCodeVerifyForXmit(result.TrasmitterCode);
                    result.ZipCodeVerify = xipResult.ZipCodeVerifyDealer;
                    result.ZipCode = xipResult.ZipCode;

任何人都知道为什么我在测试中遇到此错误?

【问题讨论】:

  • 被测方法与在实际运行环境之外似乎不起作用的实现问题紧密耦合。封装这些依赖项,以便可以模拟它们以允许单独对代码进行单元测试。
  • 还应调查错误消息的最后几行。您是否缺少测试项目中应该存在的配置信息。
  • 我不太确定测试项目中是否需要任何配置文件,因为测试项目在同一个解决方案下,并且引用了默认的webapi项目
  • 测试项目在自己的上下文中执行,需要自己的配置文件
  • 好的,我知道了,让我试试,所以我需要在我的测试项目上创建一个 app.config 并引用我的服务?

标签: c# unit-testing asp.net-web-api


【解决方案1】:

在进行单元测试时,您应该单独测试类。这是通过模拟类依赖关系来实现的。为了模拟依赖项,您应该将它们传递(注入)给类,例如通过构造函数注入。此外,您的类应该依赖于抽象(即接口或抽象类)而不是实现。这使您的代码可测试

public class UserAccountController : Controller
{
    private readonly IRServiceClient rServiceClient;

    // class does not have hidden dependencies
    public UserAccountController (IRServiceClient rServiceClient)
    {
        this.rServiceClient = rServiceClient;
    }

    public ActionResult GetVerifyLogin()
    {
        //...

        foreach (var siteItem in siteResult.ResultSet)
        {
             result.SiteNum = siteItem.SiteNum;
             result.DevNum = siteItem.DevNum;
             result.TrasmitterCode = siteItem.TransmitterCode;
        }

        // instead of creating dependency here, you are use injected dependency
        var xipResult = rServiceClient.ZipCodeVerifyForXmit(result.TrasmitterCode);
        result.ZipCodeVerify = xipResult.ZipCodeVerifyDealer;
        result.ZipCode = xipResult.ZipCode;  

        //...          
    }
}

现在您可以模拟服务依赖并单独测试您的控制器。例如。使用NSubstitute(周围还有很多其他的模拟框架):

[TestMethod]
public void GetVerifyLogin_ShouldReturnUser()
{
    var rServiceClient = Substitute.For<IRServiceClient>();
    rServiceClient.ZipCodeVerifyForXmit("foo").Returns("bar"); // just an example

    var controller = new UserAccountController(rServiceClient);
    var result = controller.GetVerifyLogin("2171251", "2171251");
    Assert.IsNotNull(result);
}

这个例子展示了如何传递假依赖,它被配置为为预定义的输入返回预定义的结果。这使您的控制器测试可重复

延伸阅读:Unit tests are F.I.R.S.T.

【讨论】:

  • 非常感谢您的解释,这对我真的很有帮助,因为我是新来的测试。谢谢
  • @JoseRaulPerera :) 我强烈建议您阅读链接文章 - 遵循这些指南将大大改善您的单元测试
  • 谢谢,我一定会的。
猜你喜欢
  • 1970-01-01
  • 2014-11-16
  • 2021-04-17
  • 2017-11-27
  • 2012-11-24
  • 1970-01-01
  • 2014-09-01
  • 1970-01-01
  • 2017-06-03
相关资源
最近更新 更多