如何模拟非虚拟方法?

hbm*_*aam 32 .net c# moq

[TestMethod]
public void TestMethod1()
{
    var mock = new Mock<EmailService>();
    mock.Setup(x => x.SendEmail()).Returns(true);
    var cus = new Customer();
    var result = cus.AddCustomer(mock.Object);
    Assert.IsTrue(result);
}

public class Customer
{
    public bool AddCustomer(EmailService emailService)
    {
        emailService.SendEmail();
        Debug.WriteLine("new customer added");
        return true;
    }
}

public class EmailService
{            
    public virtual bool SendEmail()
    {
        throw  new Exception("send email failed cuz bla bla bla");
    }
}
Run Code Online (Sandbox Code Playgroud)

EmailService.SendEmail方法必须是虚拟的才能模拟它.有没有办法模拟非虚拟方法?

aqw*_*ert 22

Moq不能在类上模拟非虚方法.要么使用其他模拟框架,例如Type mock Isolator,它实际上将IL编织到您的程序集中EmailService,或者放置一个接口并模拟它.


Fel*_*ano 8

模拟非虚拟方法涉及使用低级分析器API.目前我认为唯一可用的选择是:

两者都是商业版,即使JustMock有精简版,嘲笑非虚拟方法也只有商业版.正如评论中所指出的那样,微软的研究在Pex和Moles项目中有所体现

  • 我认为你可以将Microsoft Moles/Pex/Fakes添加到该列表中.作为奖励,它是免费的. (5认同)
  • 如果您拥有visual studio的企业版,Microsoft Fakes是"免费的". (3认同)

Ale*_*r R 7

必须使用虚拟方法进行模拟的替代方法是使用接口.这样你就可以模拟出一个完整的依赖.

public interface IEmailService
{
    bool SendEmail();
    // etc...
}

public class EmailService : IEmailService
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以创建界面的IEmailService模拟,以便模拟其任何方法.当然,您必须在适当的位置更改包含EmailService对象的变量类型IEmailService.


Jam*_*gui 7

2020 年 7 月更新: pose已放弃,目前推荐为:https : //github.com/riezebosch/Unmockable 感谢@Customizer 的指出。

我也在查看https://github.com/Serg046/AutoFake,这似乎来自@Serg046 —— 使用pose。允许您替换任何方法,包括静态或非虚拟方法。相当新的项目,但完全开源 MIT 许可证。 https://github.com/tonerdo/pose