【问题标题】:C# WebApi Unit Testing and Mocking ControllersC# WebApi 单元测试和模拟控制器
【发布时间】:2012-08-01 21:24:56
【问题描述】:

我正在处理这个 WebAPI 项目,我需要为它创建单元测试。该项目的基础是使用 VS 2010 创建的,然后添加了一个 WebApi 模块。

控制器的工作方式有点妨碍测试/模拟。我正在使用 xUnit 和 Moq ,但绝对没有必要坚持使用这两个。

应用程序使用特定对象来处理数据库访问,所以我有 controllerObject 及其构造函数需要 DataAccessObject

我在模拟控制器/数据访问对时遇到问题。我尝试运行的第一个测试是 GetAllFromDataBase,但我真的不知道如何去做。

编辑:

我按照 Cuong Le 告诉我的去做了,现在整个人都在动,我真的很感激。但我遇到了另一个问题。要访问 API,有一个用户名/密码对,我的控制器使用 Thread.CurrentPrincipal.Identity.Name;我猜现在我需要设置这个值才能让它完全工作。

还有 valueServiceMock.Setup(service => service.GetValues()) .Returns(new[] { "value1", "value2" });

似乎没有工作。当代码尝试访问数据库时,由于无法获取要查找的有效用户名,因此一无所获

【问题讨论】:

  • 你不应该模拟控制器,你会模拟控制器需要的服务。如果你在嘲笑控制器,你就不会在测试控制器。这就是重点。看看这个帖子:peterprovost.org//blog/2012/06/16/…
  • 您是否检查过您是否通过构造函数传递了模拟对象,如下所示:var controller = new ValuesController(valueServiceMock.Object);

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


【解决方案1】:

为了让您的应用可测试,您需要在设计时考虑到可测试性。从技术上讲,要设计到可测试性,您的应用应该在层之间、组件之间甚至类之间尽可能松耦合。

为可测试性设计的很多提示:避免密封、静态类...但是您需要注意的最流行的事情是dependency injection pattern,而不是在其他对象的构造函数或方法中创建对象,这个对象应该注入。通过这种方式,我们可以在类之间建立松散的依赖关系,并且可以很容易地通过模拟框架来fake。特别是依赖于外部资源的对象:网络、文件或数据库。

如何使用依赖注入来注入对象:这就是为什么 IocContainer 是正确的工具,它会自动为您注入对象。我更喜欢使用的 IoC Container 是:Autofac 和 NInject。

此处将 ValueService 注入 ValuesController 的示例:

public class ValuesController : ApiController
{
    private readonly IValueService _valueService;

    public ValuesController(IValueService valueService)
    {
        _valueService = valueService;
    }

    public string[] Get()
    {
        return _valueService.GetValues();
    }

    public string Get(int id)
    {
        return _valueService.GetValue(id);
    }
}

以下是使用 Moq 进行单元测试的简单代码:

var valueServiceMock = new Mock<IValueService>();
valueServiceMock.Setup(service => service.GetValues())
            .Returns(new[] { "value1", "value2" });

var controller = new ValuesController(valueServiceMock.Object);
var values = controller.Get();

Assert.AreEqual(values.Length, 2);
Assert.AreEqual(values[0], "value1");
Assert.AreEqual(values[1], "value2");

【讨论】:

  • 我按照你说的做了,现在整个人都在动,我真的很感激。但我遇到了另一个问题。要访问 API,有一个用户名/密码对,我的控制器使用 Thread.CurrentPrincipal.Identity.Name;
  • 我希望我能在这里解决这个问题,但让我们再提出一个问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-15
  • 2014-07-30
  • 1970-01-01
相关资源
最近更新 更多