如何解决模拟测试 SqlDataReader 结果
我有一个与员工合作的应用程序。所以我决定使用 Mock 来测试 Employee Repository。
这是我的测试方法
class EmployeesRepository : IEmployeeRepository ...
public IEnumerable<Employee> GetAllEmployees()
{
List<Employee> list = new List<Employee>();
try
{
string connectionString = _secureConfig.Value.MyDbSetting;
string sql = "select id,firstname,lastname,entrydate,email from empoyees";
using sqlConnection connection = new sqlConnection(connectionString);
using sqlCommand command = new sqlCommand(sql,connection);
connection.open();
using sqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
list.Add(new Employee
{
Id = reader.GetString(0),FirstName = reader.GetString(1),LastName = reader.GetString(2),EntryDate = reader.GetDateTime(3),Email = (reader.Isdbnull(4) ? null : reader.GetString(4))
});
}
}
catch (Exception ex)
{
_log.LogError(ex,"An error is caught when getting all employees");
}
return list;
}
我的问题是在这种情况下模拟什么以及如何模拟...我应该模拟数据读取器,还是只模拟 ExecutReader 方法...请提供建议,从哪里开始测试此类方法并直接访问数据库。
解决方法
与实现细节/问题的紧密耦合使得这很难单独进行单元测试。
重构以依赖可模拟的抽象。
例如
class EmployeesRepository : IEmployeeRepository {
private readonly IDbConnectionFactory dbConnectionFactory;
//...
public EmployeesRepository(IDbConnectionFactory dbConnectionFactory /*,...*/) {
this.dbConnectionFactory = dbConnectionFactory;
//...
}
public IEnumerable<Employee> GetAllEmployees() {
List<Employee> list = new List<Employee>();
try {
string connectionString = _secureConfig.Value.MyDbSetting;
string sql = "select id,firstname,lastname,entrydate,email from empoyees";
using (IDbConnection connection = dbConnectionFactory.CreateConnection(connectionString)) {
using (IDbCommand command = connection.CreateCommand()) {
command.CommandText = sql;
connection.Open();
using (IDataReader reader = command.ExecuteReader()) {
while (reader.Read()) {
list.Add(new Employee {
Id = reader.GetString(0),FirstName = reader.GetString(1),LastName = reader.GetString(2),EntryDate = reader.GetDateTime(3),Email = (reader.IsDBNull(4) ? null : reader.GetString(4))
});
}
}
}
}
} catch (Exception ex) {
_log.LogError(ex,"An error is caught when getting all employees");
}
return list;
}
}
其中 IDbConnectionFactory
定义为
public interface IDbConnectionFactory {
///<summary>
/// Creates a connection based on the given database name or connection string.
///</summary>
IDbConnection CreateConnection(string nameOrConnectionString);
}
将在您的 DI 容器中注册的运行时实现如下所示
class SqlConnectionFactory : IDbConnectionFactory {
public IDbConnection CreateConnection(string nameOrConnectionString) {
return new SqlConnection(nameOrConnectionString);
}
}
//...
services.AddSingleton<IDbConnectionFactory,SqlConnectionFactory>();
//...
为了测试上述内容,可以根据需要模拟抽象
public void ShouldGetAllEmployees() {
//Arrange
var readerMock = new Mock<IDataReader>();
//...setup reader members as needed
var commandMock = new Mock<IDbCommand>();
commandMock.Setup(m => m.ExecuteReader())
.Returns(readerMock.Object);
var connectionMock = new Mock<IDbConnection>();
connectionMock.Setup(m => m.CreateCommand())
.Returns(commandMock.Object);
//..Setup...
var connectionFactoryMock = new Mock<IDbConnectionFactory>();
connectionFactoryMock
.Setup(m => m.CreateConnection(It.IsAny<string>()))
.Returns(connectionMock.Object);
EmployeesRepository sut = new EmployeesRepository(connectionFactoryMock.Object);
//Act
IEnumerable<Employee> actual = sut.GetAllEmployees();
//Assert
//...assert desired behavior
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。