C# 为什么我的单元测试使用Moq';s Verify()是非确定性的吗?
我们使用MOQ4进行单元测试,特别是控制器单元测试。我们使用Moq的Verify()方法来确保记录了错误。问题是测试可以通过,但在下一次运行时失败 我们正在为我们的记录器使用Serilog 动作方法看起来像C# 为什么我的单元测试使用Moq';s Verify()是非确定性的吗?,c#,asp.net-core,moq,serilog,non-deterministic,C#,Asp.net Core,Moq,Serilog,Non Deterministic,我们使用MOQ4进行单元测试,特别是控制器单元测试。我们使用Moq的Verify()方法来确保记录了错误。问题是测试可以通过,但在下一次运行时失败 我们正在为我们的记录器使用Serilog 动作方法看起来像 public IActionResult Index(){ try{ var data = _repository.GetData(); return View(data); }catch(Exception e){ Log
public IActionResult Index(){
try{
var data = _repository.GetData();
return View(data);
}catch(Exception e){
Log.Error(e.Message);
}
}
所以单元测试使用
_mockLogger.Verify(x=> x.Write(LogEventLevel.Error,It.IsAny<string>()));
并模拟存储库,以在调用时引发异常
当它失败时,我们将收到错误消息
Moq.MoqException应至少在模拟上调用一次,但从未被调用x=>x.Write(LogEventLevel.Error,It.IsAny())
有什么想法吗?不可能完全从发布的代码中看出问题所在。我很感激为这个做一个MCVE有多难。所以我要做两个猜测 猜测1:我怀疑您出现问题的原因是代码中使用了
static
s,特别是与记录器有关
我怀疑正在发生的是,其他测试(未在文章中显示)也在修改/定义记录器的行为方式,并且由于记录器是静态的,因此测试相互干扰
尝试重新设计代码,以便使用serilog的ILogger接口将日志功能的实例依赖性注入到被测试的类中,将其存储在只读字段中,并在需要日志时使用该字段
猜测2:基于帖子中的部分内容,其中写道“…在测试的构造函数中设置”,您没有说(或标记)您正在使用哪个测试框架;但我使用的少数方法更喜欢在属性化方法中而不是在测试的构造函数中进行此类操作。例如,NUnit有OneTimeSetUp(在运行该类中的任何测试之前)、SetUp(在运行该类中的每个测试之前)、TearDown(在运行该类中的每个测试之后)、onetimeeardown(在运行该类中的所有测试之后)。您的测试的构造器可能以您不期望的顺序被调用,并且您的测试框架不支持这种顺序;而属性化方法序列是由框架保证的。从发布的代码中不可能完全看出问题所在。我很感激为这个做一个MCVE有多难。所以我要做两个猜测 猜测1:我怀疑您出现问题的原因是代码中使用了
static
s,特别是与记录器有关
我怀疑正在发生的是,其他测试(未在文章中显示)也在修改/定义记录器的行为方式,并且由于记录器是静态的,因此测试相互干扰
尝试重新设计代码,以便使用serilog的ILogger接口将日志功能的实例依赖性注入到被测试的类中,将其存储在只读字段中,并在需要日志时使用该字段
猜测2:基于帖子中的部分内容,其中写道“…在测试的构造函数中设置”,您没有说(或标记)您正在使用哪个测试框架;但我使用的少数方法更喜欢在属性化方法中而不是在测试的构造函数中进行此类操作。例如,NUnit有OneTimeSetUp(在运行该类中的任何测试之前)、SetUp(在运行该类中的每个测试之前)、TearDown(在运行该类中的每个测试之后)、onetimeeardown(在运行该类中的所有测试之后)。您的测试的构造器可能以您不期望的顺序被调用,并且您的测试框架不支持这种顺序;而属性化方法序列是由框架保证的。如果您创建了一个真正的。删除任何不需要重现问题的内容(我怀疑存储库调用是不必要的,可能是try/catch等),并展示如何设置日志记录、显示单元测试等。什么是mockLogger?一个Mock,如果它是Log的替代品,那么您确定_repository.GetData();投球和你想象的一样吗?你确定你正确地用模拟项替换了日志吗?问题是代码在我的内联网计算机上,我必须手动键入所有代码,因此没有复制粘贴:-/@mason--你是正确的:-你能确保(临时编辑)repository.GetData()始终抛出异常吗?如果你创建了一个真实的项目,它将非常有用。删除任何不需要重现问题的内容(我怀疑存储库调用是不必要的,可能是try/catch等),并展示如何设置日志记录、显示单元测试等。什么是mockLogger?一个Mock,如果它是Log的替代品,那么您确定_repository.GetData();投球和你想象的一样吗?你确定你正确地用模拟项替换了日志吗?问题是代码在我的内联网上,我必须手动键入所有代码,因此没有复制粘贴:-/@mason--你是正确的:-你能确保(临时编辑)存储库.GetData()总是抛出异常吗?由于并行性,日志是静态的,正在修改记录器。记录器是静态的,由于并行性,正在修改记录器。
var _mockLogger = new Mock<Serilog.ILogger>();
Log.Logger = _mockLogger.Object;
//...