简体   繁体   English

NUnit 测试项目的 .NET Core 容器定义

[英].NET Core container definition for NUnit test project

I am quite new to .NET Core.我对 .NET Core 很陌生。 How can I define a DI container within the NUnit class library project?如何在 NUnit 类库项目中定义DI容器?

I know that it is done through IServiceCollection , but since there isn't any Startup method, I don't know where to get the instance implementing this interface.我知道它是通过IServiceCollection完成的,但是由于没有任何Startup方法,我不知道从哪里获取实现此接口的实例。

Also I would like to be able to load definitions from other class libraries (being the subject of testing).此外,我希望能够从其他类库(作为测试的主题)加载定义。 That should be simpler as I can just create a static method in that class library with one parameter that is IServiceCollection , but again, how do I get it?这应该更简单,因为我可以在该类库中创建一个静态方法,其中一个参数是IServiceCollection ,但同样,我如何获得它?

A side question is: I presume some of the interfaces could be mocked for the purpose of tests, but how can I replace a mapping already created using of of IServiceCollection 's methods like AddSingleton or AddTransient ?一个附带问题是:我认为某些接口可以被模拟以进行测试,但是如何替换已经使用IServiceCollection的方法(如AddSingletonAddTransient创建的映射?

There is a Remove method, but it is not documented.有一个Remove方法,但没有记录。

IServiceCollection is implemented by the ServiceCollecion class. IServiceCollectionServiceCollecion类实现。 So if you want to do this for integration tests then you can use the ServiceCollection class to create your own ServiceProvider .因此,如果您想为集成测试执行此操作,那么您可以使用ServiceCollection类来创建您自己的ServiceProvider

var services = new ServiceCollection();

services.AddTransient<IMyInterface, MyClass>();
services.AddScoped<IMyScopedInteface, MyScopedClass>();
...

var serviceProvider = sc.BuildServiceProvider();

You can now use the serviceProvider instance in your tests to get your classes:您现在可以在测试中使用serviceProvider实例来获取您的类:

var myClass = serviceProvider.GetService<IMyInterface>();

If you want to mock some of the interfaces instead of using the real ones then, instead of adding the real class/interface into the service collection you can add a mock instead:如果你想模拟一些接口而不是使用真实的接口,那么你可以添加一个模拟而不是将真正的类/接口添加到服务集合中:

mockInterface = new Mock<IMyInterface>();

sc.AddScoped<IMyInterface>(factory => mockInterface.Object);

Generally you don't want to create a DI container for your tests but, as you realise, you want to mock them instead.通常,您不想为测试创建 DI 容器,但正如您意识到的那样,您想要模拟它们。 So, for example, if this is a class you want to test:因此,例如,如果这是您要测试的类:

public class UserService
{
    private readonly IUserDatabase _userDatabase;

    public UserService(IUserDatabase userDatabase)
    {
        _userDatabase = userDatabase;
    }

    public bool DoesUserExist(int userId)
    {
        return _userDatabase.UserExists(userId);
    }
}

And this is the definition of the interface used:这是所用接口的定义:

public interface IUserDatabase
{
    bool UserExists(int userId);
}

In our tests we can mock the interface to return a specific value we want for our test:在我们的测试中,我们可以模拟接口以返回我们想要用于测试的特定值:

[TestClass]
public class UserServiceTests
{
    [TestMethod]
    public void DoesUserExist_ForValidUserId_ReturnsTrue()
    {
        var fakeUserId = 123;

        var mockUserDatabase = new Mock<IUserDatabase>();
        mockUserDatabase.Setup(udb => udb.UserExists(fakeUserId)).Returns(true);

        var userService = new UserService(mockUserDatabase.Object);

        var result = userService.DoesUserExist(fakeUserId);

        Assert.IsTrue(result);
        mockUserDatabase.VerifyAll();
    }
}

So in this test we have used Moq to create a mock of our interface.所以在这个测试中,我们使用了Moq来创建我们界面的模拟。 We don't need to use a DI container because we are in controller of creating the class we are testing.我们不需要使用 DI 容器,因为我们在创建我们正在测试的类的控制器中。 The DI container is of more use in production as it enables the application to create any dependencies it needs without your code having to call new - which is a big problem if you are trying to unit test your classes. DI 容器在生产中更有用,因为它使应用程序能够创建它需要的任何依赖项,而无需您的代码调用new - 如果您尝试对类进行单元测试,这将是一个大问题。

The .VerifyAll() method checks that any methods set up on the mock object, in this case we setup a call to UserExists , was actually called. .VerifyAll()方法检查在模拟对象上设置的任何方法,在这种情况下,我们设置了对UserExists的调用,实际上被调用了。

There are plenty of examples of how to use Moq and mocking interfaces in general.有很多关于如何使用 Moq 和模拟接口的例子。 A quickstart guide to Moq is here . Moq 的快速入门指南在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM