【问题标题】:.NET Core container definition for NUnit test projectNUnit 测试项目的 .NET Core 容器定义
【发布时间】:2019-04-12 06:18:22
【问题描述】:

我对 .NET Core 还是很陌生。如何在 NUnit 类库项目中定义 DI 容器?

我知道是通过IServiceCollection完成的,但是由于没有Startup方法,所以不知道去哪里获取实现这个接口的实例。

我还希望能够从其他类库(作为测试对象)加载定义。这应该更简单,因为我可以在该类库中创建一个静态方法,其中一个参数是IServiceCollection,但同样,我如何获得它?

一个附带的问题是:我认为某些接口可以被模拟以用于测试,但是我如何替换已经使用IServiceCollection 的方法(如AddSingletonAddTransient)创建的映射?

有一个Remove 方法,但没有记录。

【问题讨论】:

    标签: c# dependency-injection .net-core nunit ioc-container


    【解决方案1】:

    通常您不想为您的测试创建一个 DI 容器,但正如您所意识到的那样,您希望改为模拟它们。因此,例如,如果这是您要测试的类:

    public class UserService
    {
        private readonly IUserDatabase _userDatabase;
    
        public UserService(IUserDatabase userDatabase)
        {
            _userDatabase = userDatabase;
        }
    
        public bool DoesUserExist(int userId)
        {
            return _userDatabase.UserExists(userId);
        }
    }
    

    这是使用的接口的定义:

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

    在我们的测试中,我们可以模拟接口以返回我们想要用于测试的特定值:

    [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();
        }
    }
    

    所以在这个测试中,我们使用Moq 来创建我们界面的模拟。我们不需要使用 DI 容器,因为我们处于创建我们正在测试的类的控制器中。 DI 容器在生产中更有用,因为它使应用程序能够创建所需的任何依赖项,而无需您的代码调用 new - 如果您尝试对类进行单元测试,这是一个大问题。

    .VerifyAll() 方法检查在模拟对象上设置的任何方法,在本例中,我们设置了对 UserExists 的调用,是否实际被调用。

    有很多关于如何使用 Moq 和一般模拟接口的示例。起订量快速入门指南是 here

    【讨论】:

    • 我没有提到这是针对集成测试而不是单元测试。上面的方法很有效,很好,可能(有时)只用于编写单类测试。上面的问题中概述了我需要的集成测试。我会假设它仍然没有答案。
    【解决方案2】:

    IServiceCollectionServiceCollecion 类实现。因此,如果您想为集成测试执行此操作,则可以使用 ServiceCollection 类创建自己的 ServiceProvider

    var services = new ServiceCollection();
    
    services.AddTransient<IMyInterface, MyClass>();
    services.AddScoped<IMyScopedInteface, MyScopedClass>();
    ...
    
    var serviceProvider = sc.BuildServiceProvider();
    

    您现在可以在测试中使用 serviceProvider 实例来获取您的类:

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

    如果你想模拟一些接口而不是使用真实的接口,那么你可以添加一个模拟来代替将真实的类/接口添加到服务集合中:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-03
      • 1970-01-01
      • 2021-07-17
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多