Moq - 调用原始方法实现但更改输入参数之一

gis*_*per 1 c# moq

我在一些集成测试中使用 Moq(更新不属于我自己的现有测试脚本和代码),并且我正在测试一个 BuinessService,其中注入了一个发送电子邮件的电子邮件接口。

public interface IEmailService
{
    void CreateMailItem(string To, string Subject, string Body);
    string GetEmailAddress(string staffmember);
}
Run Code Online (Sandbox Code Playgroud)

最初我只是 Moq'd IEmailService接口并且工作正常,但由于代码的实现方式,我需要调用默认接口实现(即EmailService)进行测试。我知道我不应该。

我知道我可以起订量如下所示的方法,但我想做的是让代码调用原始实现EmailService.CreateMailItem 并仅更改单个参数,以便将电子邮件发送到测试帐户而不是真实帐户。

var emailMock = new Mock<EmailService>() { CallBase = true };
emailMock.Setup(x => x.CreateMailItem("test@test.com", It.IsAny<string>(), It.IsAny<string>()));
email = emailMock.Object;
Run Code Online (Sandbox Code Playgroud)

我可以使用 Moq 调用原始 CreateMailItem 方法,但将“To”参数更改为我的测试电子邮件帐户并保留其他参数不变。

V0l*_*dek 5

无论你想做什么——你都做错了。

如果EmailService这是您要测试的系统,那么您永远不应该嘲笑它。Assert只需使用适当的参数和结果调用您想要测试的方法即可。

如果EmailService是一个依赖项,那么您永远不应该调用实际的实现 - 这会错过模拟某些内容的全部要点,您希望将自己与实现断开并提供一个模拟方法,该方法将简单地执行系统所期望的操作测试。

编辑:

您可以使用 Moq 并以这种方式进行破解:

var emailInstance = new EmailService():

var emailMock = new Mock<EmailService>() { CallBase = true };

emailMock.Setup(x => x.CreateMailItem(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
    .Callback((_, arg2, arg3) => emailInstance.CreateMailItem("test@test.com", arg2, arg3));
Run Code Online (Sandbox Code Playgroud)

因此,现在当您使用任何参数调用时emailMock.CreateMailItem会将调用重定向到实际实例,并与您的测试电子邮件交换第一个参数。

请注意,此类测试称为集成测试。您实际上是在实时(尽管是预制的)环境中测试模块如何相互交互。如果您可以强制被测系统使用测试电子邮件而不是使用模拟,可能会更好,但这应该可以完成工作。