C#WebApi单元测试和模拟控制器

C#WebApi单元测试和模拟控制器,c#,unit-testing,asp.net-web-api,moq,xunit,C#,Unit Testing,Asp.net Web Api,Moq,Xunit,我正在从事这个WebAPI项目,我需要为它创建单元测试。该项目的基础是使用VS2010创建的,然后添加了一个WebApi模块 控制器的工作方式有点妨碍了测试/模拟。我正在使用xUnit和Moq,但绝对没有必要坚持使用这两个 应用程序使用特定对象来处理数据库访问,因此 controllerObject及其构造函数需要DataAccessObject 我在模拟控制器/数据访问对时遇到问题。我尝试运行的第一个测试是GetAllFromDataBase,但我对如何执行它一无所知 编辑: 我做了聪乐告诉我

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

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

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

我在模拟控制器/数据访问对时遇到问题。我尝试运行的第一个测试是GetAllFromDataBase,但我对如何执行它一无所知

编辑:

我做了聪乐告诉我的事情,现在整个过程都在进行中,我真的很感激。但我陷入了另一个问题。要访问API,有一个用户名/密码对,我的控制器使用Thread.CurrentPrincipal.Identity.Name;现在我需要设置这个值,我想它才能完全工作

还有valueServiceMock.Setup(service=>service.GetValues()) .返回(新的[]{“value1”,“value2”})


似乎不起作用。由于代码试图访问数据库,但由于无法获得有效的用户名来查找,因此一无所获。为了使您的应用程序可测试,您需要考虑可测试性设计。从技术上讲,要设计可测试性,您的应用程序应在层间尽可能松耦合,在组件之间,甚至在类之间

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

如何使用依赖项注入来注入对象:这就是为什么IocContainer是合适的工具,它会自动为您注入对象。我更喜欢使用的IoC容器是:和

将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");
var valueServiceMock=new Mock();
valueServiceMock.Setup(服务=>service.GetValues())
.返回(新的[]{“value1”,“value2”});
var控制器=新的ValuesController(valueServiceMock.Object);
var values=controller.Get();
Assert.AreEqual(value.Length,2);
Assert.AreEqual(值[0],“值1”);
Assert.AreEqual(值[1],“值2”);

你不应该模仿控制器,你应该模仿控制器需要的服务。如果你在模仿控制器,你就不会测试控制器。这就是重点。看看这篇文章:您是否检查过通过构造函数传递mock对象,如下所示:var controller=newvaluescocontroller(valueServiceMock.object);我照你说的做了,现在一切都在进行中,我真的很感激。但我陷入了另一个问题。要访问API,有一个用户名/密码对,我的控制器使用Thread.CurrentPrincipal.Identity.Name;我希望我能在这里解决这个问题,但是让我们再问一个问题吧!