2012-07-31 148 views
21
[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"); 
    } 
} 

EmailService.SendEmail方法必须虚拟来模拟它。有什么办法来模拟非虚拟方法吗?如何模拟非虚拟方法?

回答

16

Moq无法模拟类上的非虚拟方法。可以使用其他模拟框架,如Type mock Isolator,它们实际上将IL编织到您的程序集中,或者将接口放在EmailService上,然后模拟它。

4

必须使用虚拟方法进行模拟的替代方法是使用接口。这样你可以嘲笑整个依赖。现在

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

public class EmailService : IEmailService 
{ 
    //... 
} 

您可以创建界面IEmailService的嘲笑,让你嘲笑它的任何方法。当然,您必须在适当的情况下将包含EmailService对象的变量类型更改为IEmailService

+0

我认为使用这种技术很好,而且使用接口肯定有优势。但是如果你在两种选择之间评估非虚拟方法是可嘲弄的:1)使其成为虚拟的,2)将它用作接口的一部分,2的优势是什么?即使你选择了2,那么你也有效地使该方法成为虚拟的,因为它现在成为界面的一部分。 – zumalifeguard 2015-06-25 17:10:40

7

模拟非虚拟方法涉及使用低级别探查器API。此刻,我觉得唯一可用的选项是:

都是商业的,即使JustMock有精简版版,嘲讽非虚方法可正好与商业版。 正如在评论中指出有一些来自微软的研究,在项目Pex and Moles

+5

我认为你可以添加微软鼹鼠/ Pex/Fakes到该列表。作为奖励,它是免费的。 – podiluska 2012-07-31 10:43:08

+0

假货不包含在VS的快递版本中。 – 2015-08-19 23:30:00

1

由于@aqwert和@Felice使用Typemock Isolator它是可能的(很容易),当嘲笑没有添加或更改任何代码非虚方法写,例如:

[TestMethod,Isolated] 
    public void TestMethod1() 
    { 
     var mock = Isolate.Fake.Instance<EmailService>(); 
     Isolate.WhenCalled(() => mock.SendEmail()).WillReturn(true); 
     var cust = new Customer(); 
     var result = cust.AddCustomer(mock); 
     Assert.IsTrue(result); 
    } 

正如您所看到的我创建的测试与您尝试创建的测试类似。