【发布时间】:2021-08-01 04:02:55
【问题描述】:
Visual Studio 2019 企业版 16.9.4;最小起订量 4.16.1; xunit 2.4.1; net5.0
我正在尝试对我的AlbumData.GetAlbumsAsync() 方法进行单元测试。我模拟了SqlDataAccess 层,它在generic 方法中使用Dapper 调用数据库。
这是我的设置。模拟不起作用。在 AlbumData.GetAlbumsAsync() 方法中,对模拟对象 (_sql.LoadDataAsync) 的调用返回 null 并且 output 设置为 null。
谁能告诉我我做错了什么?
SqlDataAccess.cs
public async Task<List<T>> LoadDataAsync<T, U>(string storedProcedure,
U parameters, string connectionStringName)
{
string connectionString = GetConnectionString(connectionStringName);
using (IDbConnection connection = new SqlConnection(connectionString))
{
IEnumerable<T> result = await connection.QueryAsync<T>(storedProcedure, parameters,
commandType: CommandType.StoredProcedure);
List<T> rows = result.ToList();
return rows;
}
}
相册数据.cs
public class AlbumData : IAlbumData
{
private readonly ISqlDataAccess _sql;
public AlbumData(ISqlDataAccess sql)
{
_sql = sql;
}
public async Task<List<AlbumModel>> GetAlbumsAsync()
{
var output = await _sql.LoadDataAsync<AlbumModel, dynamic>
("dbo.spAlbum_GetAll", new { }, "AlbumConnection");
return output;
}
...
}
AlbumDataTest.cs
public class AlbumDataTest
{
private readonly List<AlbumModel> _albums = new()
{
new AlbumModel { Title = "Album1", AlbumId = 1 },
new AlbumModel { Title = "Album2", AlbumId = 2 },
new AlbumModel { Title = "Album3", AlbumId = 3 }
};
[Fact]
public async Task getAlbums_returns_multiple_records_test()
{
Mock<ISqlDataAccess> sqlDataAccessMock = new();
sqlDataAccessMock.Setup(d => d.LoadDataAsync<AlbumModel, dynamic>
(It.IsAny<string>(), new { }, It.IsAny<string>()))
.Returns(Task.FromResult(_albums));
AlbumData albumData = new AlbumData(sqlDataAccessMock.Object);
List<AlbumModel> actual = await albumData.GetAlbumsAsync();
Assert.True(actual.Count == 3);
}
...
}
更新1:
根据@freeAll 和@brent.reynolds 的建议,我更新了测试以使用It.IsAny<string>()
还更新了@brent.reynolds fiddle 以实际实施单元测试:
https://dotnetfiddle.net/nquthR
这一切都在小提琴中有效,但是当我将完全相同的测试粘贴到我的 AlbumDataTest 中时,它仍然返回 null。 Assert.Null(actual); 通过,Assert.True(actual.Count == 3); 失败。
更新 2:
我已将一个测试失败的项目发布到https://github.com/PerProjBackup/Failing-Mock。
如果您运行 API.Library.ConsoleTests 项目,则 Mock 可以工作。如果您在 API.Library.Tests 项目中使用 Test Explorer 运行测试,则 Mock 会失败。
@brent.reynolds 能够通过将 dynamic 泛型更改为 object 来让 Mock 工作。现在尝试调试dynamic 问题。
更新3:
如果我将AlbumData 类移动到与AllbumDataTest 类相同的项目中,则模拟工作(使用dynamic)返回包含三个对象的列表。但是当AlbumData 类在一个单独的项目中时(就像在现实世界中一样),mock 会返回 null。
我已更新 https://github.com/PerProjBackup/Failing-Mock 存储库。我删除了控制台应用程序并创建了一个包含两种方案的 Failing 和 Passing 文件夹。
为什么将模拟传递给不同项目的类会导致模拟失败?
更新4:
请参阅 brent.reynolds 接受的答案和我的评论。问题是在模拟设置中使用了匿名对象。我已经删除了 Failing-Mock 存储库和 dotnetfiddle。
【问题讨论】: