gpt4 book ai didi

c# - 如何正确模拟 MongoDb 客户端

转载 作者:太空宇宙 更新时间:2023-11-03 22:31:14 25 4
gpt4 key购买 nike

上下文

我正在为我一直在开发的 API 编写单元测试,但在尝试对访问 MongoDB 存储的“上下文”进行单元测试时遇到了一个问题。

我为我的上下文抽象了当前接口(interface):

public interface IProjectsContext
{
IMongoCollection<Project> Projects { get; }
}

我能够成功地使用此接口(interface)以及 Moq 对我的存储库进行单元测试。

但是,在尝试对我的 Context 的实现进行单元测试时,我一直无法找到一个解决方案来模拟内部:

public class ProjectsContext : IProjectsContext
{
private const string ProjectsCollectionName = "Projects";

private readonly IDatabaseParameters _dbParams;
private readonly MongoClient _client;
private readonly IMongoDatabase _database;

private IMongoCollection<Project> _projects;

public ProjectsContext(IDatabaseParameters dbParams)
{
_dbParams = dbParams ?? throw new ArgumentNullException(nameof(dbParams));
_client = new MongoClient(_dbParams.ConnectionString);
_database = _client.GetDatabase(_dbParams.DatabaseName);
}

public IMongoCollection<Project> Projects
{
get
{
if (_projects is null)
_projects = _database.GetCollection<Project>(ProjectsCollectionName);
return _projects;
}
}
}

有问题的单元测试是:

private readonly Fixture _fixture = new Fixture();
private readonly Mock<IDatabaseParameters> _dbParametersMock = new Mock<IDatabaseParameters>();

public ProjectsContextTests()
{

}

[Fact(DisplayName = "Create a Project Context")]
public void CreateProjectContext()
{
// Arrange
_dbParametersMock.Setup(m => m.ConnectionString).Returns(_fixture.Create<string>());
_dbParametersMock.Setup(m => m.DatabaseName).Returns(_fixture.Create<string>());

// Act
var result = new ProjectsContext(_dbParametersMock.Object);

// Assert
result.Should().NotBeNull();
result.Should().BeAssignableTo<IProjectsContext>();
// TODO: Write a test to assert the ProjectCollection
}

问题

我能想到的唯一解决方案是更改我的 ProjectsContext 以具有一个构造函数,该构造函数接收将要使用的 IMongoDatabase 作为参数。然而,这是唯一的解决方案吗?

使用的库

我将以下 NuGet 用于我的单元测试和实现:

  • 单位
  • Coverlet.msbuild
  • 起订量
  • 自动夹具
  • 流利的断言
  • MongoDB

最佳答案

ProjectsContext 与实现问题/细节紧密耦合(即: MongoClient),这使得测试变得孤立难的。

IMongoDatabase 是真正的依赖项,应该显式注入(inject)到目标类中。

引用 Explicit Dependencies Principle

public class ProjectsContext : IProjectsContext {
private const string ProjectsCollectionName = "Projects";
private readonly IMongoDatabase database;
private IMongoCollection<Project> projects;

public ProjectsContext(IMongoDatabase database) {
this.database = database;
}

public IMongoCollection<Project> Projects {
get {
if (projects is null)
projects = database.GetCollection<Project>(ProjectsCollectionName);
return projects;
}
}
}

至于数据库的创建/初始化,那个实现细节可以移到组合根

//...ConfigureServices

services.AddScoped<IMongoDatabase>(sp => {
var dbParams = sp.GetRequiredService<IDatabaseParameters>();
var client = new MongoClient(dbParams.ConnectionString);
return client.GetDatabase(dbParams.DatabaseName);
});

//...

目标类的测试现在可以独立完成,而不会出现来自第 3 方实现问题的意外行为

[Fact(DisplayName = "Create a Project Context")]
public void CreateProjectContext() {
// Arrange
var collectionMock = Mock.Of<IMongoCollection<Project>>();
var dbMock = new Mock<IMongoDatabase>();
dbMock.Setup(_ => _.GetCollection<Project>(It.IsAny<string>()))
.Returns(collectionMock);

// Act
var result = new ProjectsContext(dbMock.Object);

// Assert
result.Should().NotBeNull()
.And.BeAssignableTo<IProjectsContext>();
//Write a test to assert the ProjectCollection
result.Projects.Should().Be(collectionMock);
}

关于c# - 如何正确模拟 MongoDb 客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57636539/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com