NUnit 测试项目的 .NET Core 容器定义
.NET Core container definition for NUnit test project
我是 .NET Core 的新手。如何在 NUnit class 库项目中定义 DI 容器?
我知道是通过IServiceCollection
完成的,但是由于没有Startup
方法,所以我不知道从哪里得到实现这个接口的实例。
我还希望能够从其他 class 库(作为测试对象)加载定义。这应该更简单,因为我可以在那个 class 库中创建一个静态方法,其中一个参数是 IServiceCollection
,但同样,我如何获得它?
一个附带的问题是:我假设某些接口可以出于测试目的而被模拟,但是我如何才能替换已经使用 IServiceCollection
的方法创建的映射,例如 AddSingleton
或 AddTransient
?
有一个Remove
方法,但没有记录。
通常您不想为您的测试创建一个 DI 容器,但正如您所意识到的,您想要模拟它们。因此,例如,如果这是您要测试的 class:
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);
}
在我们的测试中,我们可以将接口模拟为 return 我们想要用于测试的特定值:
[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 容器,因为我们在创建我们正在测试的 class 的控制器中。 DI 容器在生产中有更多用途,因为它使应用程序能够创建它需要的任何依赖项,而无需您的代码调用 new
- 如果您尝试对 class 进行单元测试,这是一个大问题es.
.VerifyAll()
方法检查在模拟对象上设置的任何方法,在本例中我们设置对 UserExists
的调用,是否实际被调用。
一般来说,有很多关于如何使用 Moq 和模拟接口的示例。 Moq 快速入门指南是 here.
IServiceCollection
是由ServiceCollecion
class实现的。因此,如果您想为集成测试执行此操作,则可以使用 ServiceCollection
class 创建您自己的 ServiceProvider
.
var services = new ServiceCollection();
services.AddTransient<IMyInterface, MyClass>();
services.AddScoped<IMyScopedInteface, MyScopedClass>();
...
var serviceProvider = sc.BuildServiceProvider();
您现在可以在测试中使用 serviceProvider
实例来获取 classes:
var myClass = serviceProvider.GetService<IMyInterface>();
如果您想模拟某些接口而不是使用真实的接口,那么您可以添加一个模拟而不是将真实的 class/interface 添加到服务集合中:
mockInterface = new Mock<IMyInterface>();
sc.AddScoped<IMyInterface>(factory => mockInterface.Object);
我是 .NET Core 的新手。如何在 NUnit class 库项目中定义 DI 容器?
我知道是通过IServiceCollection
完成的,但是由于没有Startup
方法,所以我不知道从哪里得到实现这个接口的实例。
我还希望能够从其他 class 库(作为测试对象)加载定义。这应该更简单,因为我可以在那个 class 库中创建一个静态方法,其中一个参数是 IServiceCollection
,但同样,我如何获得它?
一个附带的问题是:我假设某些接口可以出于测试目的而被模拟,但是我如何才能替换已经使用 IServiceCollection
的方法创建的映射,例如 AddSingleton
或 AddTransient
?
有一个Remove
方法,但没有记录。
通常您不想为您的测试创建一个 DI 容器,但正如您所意识到的,您想要模拟它们。因此,例如,如果这是您要测试的 class:
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);
}
在我们的测试中,我们可以将接口模拟为 return 我们想要用于测试的特定值:
[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 容器,因为我们在创建我们正在测试的 class 的控制器中。 DI 容器在生产中有更多用途,因为它使应用程序能够创建它需要的任何依赖项,而无需您的代码调用 new
- 如果您尝试对 class 进行单元测试,这是一个大问题es.
.VerifyAll()
方法检查在模拟对象上设置的任何方法,在本例中我们设置对 UserExists
的调用,是否实际被调用。
一般来说,有很多关于如何使用 Moq 和模拟接口的示例。 Moq 快速入门指南是 here.
IServiceCollection
是由ServiceCollecion
class实现的。因此,如果您想为集成测试执行此操作,则可以使用 ServiceCollection
class 创建您自己的 ServiceProvider
.
var services = new ServiceCollection();
services.AddTransient<IMyInterface, MyClass>();
services.AddScoped<IMyScopedInteface, MyScopedClass>();
...
var serviceProvider = sc.BuildServiceProvider();
您现在可以在测试中使用 serviceProvider
实例来获取 classes:
var myClass = serviceProvider.GetService<IMyInterface>();
如果您想模拟某些接口而不是使用真实的接口,那么您可以添加一个模拟而不是将真实的 class/interface 添加到服务集合中:
mockInterface = new Mock<IMyInterface>();
sc.AddScoped<IMyInterface>(factory => mockInterface.Object);