gpt4 book ai didi

unit-testing - 如何使用 Moq.Dapper 模拟 QueryMultiple

转载 作者:行者123 更新时间:2023-12-02 03:28:49 24 4
gpt4 key购买 nike

我正在编写单元测试用例,并且成功地为 Query 编写了单元测试用例。但是我没有为 QueryMultiple 编写单元测试用例。

对于查询,我是这样写的:

 IEnumerable<ClientTestPurpose> fakeTestPurposes = new 
List<ClientTestPurpose>()
{
new ClientTestPurpose { PurposeID = 1, PurposeName = "Test Purpose name1"},
new ClientTestPurpose { PurposeID = 1, PurposeName = "Test Purpose name2"},
new ClientTestPurpose { PurposeID = 1, PurposeName = "Test Purpose name3"}
};

_mock.SetupDapper(x => x.Query<ClientTestPurpose>(It.IsAny<string>(), null, null, true, null, null)).Returns(fakeTestPurposes);

var result = _libraryRepository.TestPurposes(clientModal.Id);

Assert.IsNotNull(result);
Assert.AreEqual(result.Count(), fakeTestPurposes.Count());

如何为QueryMultiple编写:

using (var multi = _db.QueryMultiple(spName, spParams, commandType: CommandType.StoredProcedure))
{
var totals = multi.Read<dynamic>().FirstOrDefault();
var aggregates = multi.Read<StatusModel>();
var scripts = multi.Read<LibraryItemModel>();
var runs = multi.Read<RunSummaryModel>();
var filteredTotals = multi.Read<dynamic>().FirstOrDefault();
}

最佳答案

显然您使用了 Moq.Dapper 扩展。以下是 SetupDapperSetupDapperAsync 方法的代码:

public static ISetup<IDbConnection, TResult> SetupDapper<TResult>(this Mock<IDbConnection> mock, Expression<Func<IDbConnection, TResult>> expression)
{
MethodCallExpression body = expression.Body as MethodCallExpression;
if ((body != null ? body.Method.DeclaringType : (Type) null) != typeof (SqlMapper))
throw new ArgumentException("Not a Dapper method.");
string name = body.Method.Name;
if (name == "Execute")
return (ISetup<IDbConnection, TResult>) DbConnectionInterfaceMockExtensions.SetupExecute(mock);
if (name == "ExecuteScalar")
return DbConnectionInterfaceMockExtensions.SetupExecuteScalar<TResult>(mock);
if (name == "Query" || name == "QueryFirstOrDefault")
return DbConnectionInterfaceMockExtensions.SetupQuery<TResult>(mock);
throw new NotSupportedException();
}

public static ISetup<IDbConnection, Task<TResult>> SetupDapperAsync<TResult>(this Mock<IDbConnection> mock, Expression<Func<IDbConnection, Task<TResult>>> expression)
{
MethodCallExpression body = expression.Body as MethodCallExpression;
if ((body != null ? body.Method.DeclaringType : (Type) null) != typeof (SqlMapper))
throw new ArgumentException("Not a Dapper method.");
if (body.Method.Name == "QueryAsync")
return DbConnectionInterfaceMockExtensions.SetupQueryAsync<TResult>(mock);
throw new NotSupportedException();
}

如您所见,Moq.Dapper 仅支持对 ExecuteExecuteScalarQueryQueryAsync 方法进行模拟.因此,您可能会在尝试模拟 QueryMultiple 时遇到 NotSupportedException。要模拟数据库行为,您可能需要首先引入另一个抽象级别,正如@TrueWill 在评论中所说。这只是您的情况下的想法示例:

[Test]
public void DoSomethingWithQueryTest()
{
// Arrange
IEnumerable<ClientTestPurpose> fakeTestPurposes = new
List<ClientTestPurpose>
{
new ClientTestPurpose { PurposeID = 1, PurposeName = "Test Purpose name1" },
new ClientTestPurpose { PurposeID = 1, PurposeName = "Test Purpose name2" },
new ClientTestPurpose { PurposeID = 1, PurposeName = "Test Purpose name3" }
};

var mock = new Mock<ILibraryRepository>();
mock.Setup(x => x.TestPurposes(It.IsAny<int>())).Returns(fakeTestPurposes);
var logicService = new SomeLogicService(mock.Object);

// Act
var result = logicService.DoSomethingWithQuery(1);

// Assert
Assert.IsNotNull(result);
Assert.AreEqual(result.Count(), fakeTestPurposes.Count());
}

[Test]
public void DoSomethingWithQueryMultipleTest()
{
// Arrange
SomeAggregate fakeTestPurposes = new SomeAggregate();

var mock = new Mock<ILibraryRepository>();
mock.Setup(x => x.TestQueryMultiple()).Returns(fakeTestPurposes);
var logicService = new SomeLogicService(mock.Object);

// Act
var result = logicService.DoSomethingWithQueryMultiple();

// Assert
Assert.IsNotNull(result);
}

public interface ILibraryRepository
{
IEnumerable<ClientTestPurpose> TestPurposes(int id);
SomeAggregate TestQueryMultiple();
}

public class LibraryRepository : ILibraryRepository
{
private readonly IDbConnection _db;

public LibraryRepository(IDbConnection db)
{
_db = db ?? throw new ArgumentNullException(nameof(db));
}

public IEnumerable<ClientTestPurpose> TestPurposes(int id)
{
return _db.Query<ClientTestPurpose>("SQL here", new { id }, null, true, null, null);
}

public SomeAggregate TestQueryMultiple()
{
string spName = "SQL here";
var spParams = new { Id = 1 };
using (var multi = _db.QueryMultiple(spName, spParams, commandType: CommandType.StoredProcedure))
{
return new SomeAggregate
{
totals = multi.Read<dynamic>().FirstOrDefault(),
aggregates = multi.Read<StatusModel>(),
scripts = multi.Read<LibraryItemModel>(),
runs = multi.Read<RunSummaryModel>(),
filteredTotals = multi.Read<dynamic>().FirstOrDefault()
};
}
}
}

public class SomeAggregate
{
public IEnumerable<dynamic> totals { get; set; }
public IEnumerable<StatusModel> aggregates { get; set; }
public IEnumerable<LibraryItemModel> scripts { get; set; }
public IEnumerable<RunSummaryModel> runs { get; set; }
public IEnumerable<dynamic> filteredTotals { get; set; }
}

/// <summary>
/// Example logic server, that just returns results from repository
/// </summary>
public class SomeLogicService
{
private readonly ILibraryRepository _repo;

public SomeLogicService(ILibraryRepository repo)
{
_repo = repo;
}

public IEnumerable<ClientTestPurpose> DoSomethingWithQuery(int id)
{
return _repo.TestPurposes(id);
}

public SomeAggregate DoSomethingWithQueryMultiple()
{
return _repo.TestQueryMultiple();
}
}

主要思想是将所有数据库特定的东西隐藏在 ILibraryRepository 后面,并将您需要测试的所有逻辑移动到某个逻辑服务器,该服务器将接收存储库作为依赖项。为了存储库中的代码应该简单、明显,包含所有 DB 特定逻辑:连接、事务、命令、对象关系映射等。并且您不需要用 unt 测试覆盖这些代码。然而,你确实用单元测试覆盖了 SomeLogicService 的代码,因为这是你真正需要测试的。你会看到 Dapper 扩展方法是相当低级的抽象,它没有隐藏使用 DB 的细节,它们只是帮助者。希望能帮助到你。

关于unit-testing - 如何使用 Moq.Dapper 模拟 QueryMultiple,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52414562/

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