【发布时间】:2021-04-22 12:59:16
【问题描述】:
我有一个使用以下方法的存储库DoSomeWork:
internal class MyRepository : IMyRepository
{
public MyRepository(ILogger<MyRepository> logger, IDbContextWrapper dbContext)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
this.dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
}
public Task<Result> DoSomeWork(int someInt)
{
return Task.Run(() =>
{
try
{
var parameters = new DynamicParameters(new { SomeIntValue = someInt });
parameters.Add("WorkComplete", DbType.Boolean, direction: ParameterDirection.ReturnValue);
dbContext.TransactionedExecute("NameOfStoredProcedure", parameters, CommandType.StoredProcedure); //This is a wrapper for Dapper (DbConnection)
var status = (DoSomeWorkStatus)parameters.Get<int>("WorkComplete");
var workComplete = status == DoSomeWorkStatus.DoneSuccessfully;
return workComplete ? Result.WorkDone : Result.NoWorkDone;
}
catch(DatabaseTimeoutException dte)
{
logger.LogInformation(dte, "");
return Result.Error;
}
catch(DatabaseDeadlockException dde)
{
logger.LogInformation(dde, "");
return Result.Error;
}
});
}
}
我想要实现的是测试和验证一旦 DatabaseTimeoutException 或 DatabaseDeadlockException 在 try/catch 中被捕获,任务应该返回 Result.Error。所有这一切都应该一步完成(无需重试)。
在测试中我有以下内容:
private Mock<IMyRepository> myRepoMock;
private MyRepoManager target;
...
[SetUp]
public void SetUp()
{
myRepoMock = new Mock<IMyRepository>();
target = new MyRepoManager(myRepoMock.Object);
}
[Test]
public async Task MyMoqTest()
{
//Arrange
myRepoMock
.Setup(mrm => mrm.DoSomeWork(It.IsAny<int>()))
.Returns(Task.FromException<Result>(new DatabaseTimeoutException()));
//myRepoMock
// .Setup(mrm => mrm.DoSomeWork(It.IsAny<int>()))
// .Throws<DatabaseTimeoutException>(); <- The same result as above
//Act
Result taskResult = await target.RunTask(int someInt); //Calls repository method - DoSomeWork
//Assert
Assert.AreEqual(Result.Error, taskResult.Result);
}
但是发生的情况是存储库抛出 DatabaseTimeoutException 而不返回 Result.Error,并且测试失败并显示消息(如预期的那样):
MyExceptions.DatabaseTimeoutException : Exception of type 'MyExceptions.DatabaseTimeoutException' was thrown.
我对 Moq 很陌生,所以我的问题是 - 这可以用 Moq 完成吗?如果可以,我将如何去做?
谢谢。
【问题讨论】:
-
您似乎误解了 mocking 的工作原理。您不需要“强制例外”。您所要做的就是模拟行为 - 这意味着您可以让您的模拟返回您想要的结果(Result.Error),而无需涉及异常。
-
我想添加到@mason 的答案,如果你想测试 MyRepository 中的一些逻辑 - 你不应该模拟那个类。您应该创建一个实际的实现,但要使用模拟的依赖项(DbContext 和 Logger)。如果你想测试 catch 中的行为,你可以设置 DbContext mock 来抛出异常,然后调用 MyRepository.DoSomeWork 并检查它会返回什么。
-
谢谢@GoodboY,我做到了,它按预期工作。