首页 > 解决方案 > Moq - 调用原始方法实现但更改输入参数之一

问题描述

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

public interface IEmailService
{
    void CreateMailItem(string To, string Subject, string Body);
    string GetEmailAddress(string staffmember);
}

最初我只是 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;

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

标签: c#moq

解决方案


不管你想做什么——你做错了。

如果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));

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

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


推荐阅读