模拟方法执行真实代码而不是模拟,为什么?
Mocked method executes the real code instead the mock, why?
我正在使用 .CallBase() 来执行 .Export() 方法的模拟背后的真实代码在 TsExporter class.
内
另一方面,.RetrieveTranslations() 也在执行真实代码,而不是返回模拟值 "I told it to do it"。
代码如下:
[TestFixture]
public class TestClass
{
private Mock<ITsExporter> _tsExporter;
[SetUp]
public void SetUp()
{
_tsExporter = new Mock<TsExporter>().As<ITsExporter>();
//This is calling the real code which is good
_tsExporter.Setup(x => x.Export(It.IsAny<TsFileModel>(), It.IsAny<string>()))
.CallBase();
//but this is calling the real code too, and I was expecting not to
//call it and return the mock instead...
_tsExporter.Setup(x => x.RetrieveTranslations(It.IsAny<DataTable>(),
It.IsAny<string>(), It.IsAny<string>()))
.Returns(new DataTable());
}
[Test]
public void Test()
{
_tsExporter.Object.Export(new TsFileModel(), "");
}
}
我错过了什么?
谢谢!
您不应该模拟您正在测试的 class,而是模拟 class 的依赖项,以更改它们产生的输出以及它们如何影响您正在使用的代码 运行。单元测试应该只测试代码的单个逻辑位。
看看这个关于如何模拟的简单教程:https://developerhandbook.com/unit-testing/writing-unit-tests-with-nunit-and-moq/
更新
我认为您不应该模拟数据库连接,或者将访问数据库内容的 class 抽象到存储库并模拟它。
另一个问题是您使用的是哪种 Db 访问权限?英孚?小巧玲珑?有一些方法可以模拟这些并测试您的 class 如何处理来自这些的各种 returns。
例如 EF:
How to mock EntityFramework Database created by codefirst strategy? and How are people unit testing with Entity Framework 6, should you bother?
更新
您认为它是要调用真正的实现或基础 class 实现是正确的。
但是,除非您尝试编写集成测试,否则它不适用于您的情况。如果您正在编写单元测试,您应该独立于其他 class 实际输出来测试单个工作单元。我认为什么是 CallBase 功能是另一个问题。在我的理解中,它意味着调用你继承的 class 来测试该功能,但你仍然不应该通过模拟实现它的 class 来测试它,如果它是抽象的 class 你不应该通过模拟测试 class 来测试它,否则你正在测试一个不同的 class。要么更改 class,要么不对其进行测试,要么返工您原来的 class 以调用那个并查看它的输出。据我所知,最重要的是你正在调用 base 来模拟连接字符串或类似的东西,这对 运行 代码没有影响,或者至少它不应该因为你正在模拟输出,否则这已经是集成测试了。
关于它的好文章是:http://www.codenutz.com/unit-testing-mocking-base-class-methods-with-moq/
嘲笑很好。
我缺少的是在 class 中使 RetrieveTranslations() virtual 处于测试状态。
因此,以这种方式,除了 RetrieveTranslations() 方法之外,真正的代码被执行,该方法将 return 无论模拟告诉它什么 return。
这不是一个好方法,正如人们在评论中也提到的那样,我们不应该嘲笑正在测试的 class 但如果有人出于某种原因需要这个,这就是方法你可以的。
PS:我重构了 class 这样我就不必模拟这个 class 而是它的依赖项,并在需要的地方注入它们。
我正在使用 .CallBase() 来执行 .Export() 方法的模拟背后的真实代码在 TsExporter class.
内另一方面,.RetrieveTranslations() 也在执行真实代码,而不是返回模拟值 "I told it to do it"。
代码如下:
[TestFixture]
public class TestClass
{
private Mock<ITsExporter> _tsExporter;
[SetUp]
public void SetUp()
{
_tsExporter = new Mock<TsExporter>().As<ITsExporter>();
//This is calling the real code which is good
_tsExporter.Setup(x => x.Export(It.IsAny<TsFileModel>(), It.IsAny<string>()))
.CallBase();
//but this is calling the real code too, and I was expecting not to
//call it and return the mock instead...
_tsExporter.Setup(x => x.RetrieveTranslations(It.IsAny<DataTable>(),
It.IsAny<string>(), It.IsAny<string>()))
.Returns(new DataTable());
}
[Test]
public void Test()
{
_tsExporter.Object.Export(new TsFileModel(), "");
}
}
我错过了什么?
谢谢!
您不应该模拟您正在测试的 class,而是模拟 class 的依赖项,以更改它们产生的输出以及它们如何影响您正在使用的代码 运行。单元测试应该只测试代码的单个逻辑位。
看看这个关于如何模拟的简单教程:https://developerhandbook.com/unit-testing/writing-unit-tests-with-nunit-and-moq/
更新
我认为您不应该模拟数据库连接,或者将访问数据库内容的 class 抽象到存储库并模拟它。
另一个问题是您使用的是哪种 Db 访问权限?英孚?小巧玲珑?有一些方法可以模拟这些并测试您的 class 如何处理来自这些的各种 returns。
例如 EF:
How to mock EntityFramework Database created by codefirst strategy? and How are people unit testing with Entity Framework 6, should you bother?
更新
您认为它是要调用真正的实现或基础 class 实现是正确的。 但是,除非您尝试编写集成测试,否则它不适用于您的情况。如果您正在编写单元测试,您应该独立于其他 class 实际输出来测试单个工作单元。我认为什么是 CallBase 功能是另一个问题。在我的理解中,它意味着调用你继承的 class 来测试该功能,但你仍然不应该通过模拟实现它的 class 来测试它,如果它是抽象的 class 你不应该通过模拟测试 class 来测试它,否则你正在测试一个不同的 class。要么更改 class,要么不对其进行测试,要么返工您原来的 class 以调用那个并查看它的输出。据我所知,最重要的是你正在调用 base 来模拟连接字符串或类似的东西,这对 运行 代码没有影响,或者至少它不应该因为你正在模拟输出,否则这已经是集成测试了。
关于它的好文章是:http://www.codenutz.com/unit-testing-mocking-base-class-methods-with-moq/
嘲笑很好。
我缺少的是在 class 中使 RetrieveTranslations() virtual 处于测试状态。
因此,以这种方式,除了 RetrieveTranslations() 方法之外,真正的代码被执行,该方法将 return 无论模拟告诉它什么 return。
这不是一个好方法,正如人们在评论中也提到的那样,我们不应该嘲笑正在测试的 class 但如果有人出于某种原因需要这个,这就是方法你可以的。
PS:我重构了 class 这样我就不必模拟这个 class 而是它的依赖项,并在需要的地方注入它们。