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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11802331/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 19:19:49  来源:igfitidea点击:

C# WebApi Unit Testing and Mocking Controllers

c#unit-testingasp.net-web-apimoqxunit

提问by oSR

I am working on this WebAPI project and I need to create unit tests for it. The base of the project was created using VS 2010 , and then an WebApi Module was added.

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

The workings of the controller are kinda getting in the way of testing/mocking. I am using xUnit and Moq , but there is absolutely no need to stick with those two.

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

The application uses specific objects to deal with database access, so I have the controllerObject and its contructor requires the DataAccessObject

应用程序使用特定对象来处理数据库访问,所以我有控制器对象,它的构造函数需要 DataAccessObject

I am having problem with mocking the controller / dataaccess pair. The first test i′m trying to run is a GetAllFromDataBase, but i dont really have a clue on how to do it.

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

EDIT:

编辑:

I did what Cuong Le told me and the whole is moving now, i really apreciate it. But i stumped into another problem. To access the API, there is a username/password pair and my controller uses Thread.CurrentPrincipal.Identity.Name; right now i would need to set this value for it to fully work I guess.

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

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

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

does not seem to be working. as the code tries to reach for the database, and gets nothing since it cant get a valid username to look for

似乎没有工作。当代码试图访问数据库时,由于无法获得有效的用户名来查找,因此什么也得不到

采纳答案by cuongle

In order to get your app testable, you need to design for testability in mind.Technically, to design to testability, your app should be loose coupling as much as possible between layers, between components and even between classes.

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

A lot of hints to design for testability: avoid sealed, static class... But the most popular thing you need to be aware of is dependency injection pattern, instead of creating object inside contructors or methods of other objects, this object should be injected. With this way we make loose dependency between class and easy for us to fakeby mocking framework. Esp, for the objects which depend on external resource: network, file or database.

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

How to inject object by using dependency injection: that's why IocContainer is the right tool for this, it will inject objects for you automatically. IoC Container which I prefer to use is: Autofacand NInject.

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

Example in here to inject ValueService into ValuesController:

此处的示例将 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);
    }
}

And below is the simple code to unit test with Moq:

下面是使用 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");