How to mock non virtual methods?

情到浓时终转凉″ 提交于 2019-11-26 04:51:17

问题


[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\");
    }
}

The EmailService.SendEmail method must be virtual to mock it. Is there any way to mock non virtual methods?


回答1:


Moq cannot mock non virtual methods on classes. Either use other mocking frameworks such as Type mock Isolator which actually weaves IL into your assembly or place an interface on EmailService and mock that.




回答2:


Mocking non virtual methods involves the use of low level profiler API. At the moment I think the only options available are :

  • TypeMock
  • JustMock

both are commercial, even if JustMock have a lite edition, mocking non virtual methods are available just with the commercial version. As pointed in the comments there is something from Microsoft research, in the project Pex and Moles




回答3:


The alternative to having to use virtual methods for mocking is to use interfaces. This way you can mock out a whole dependency.

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

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

Now you can create mocks of the interface IEmailService to let you mock any of its methods. Of course, you'll have to change the types of variables containing EmailService objects to IEmailService where appropriate.




回答4:


Use pose. Allows you to replace any method including static or non virtual. Fairly new project, but fully open source MIT license. https://github.com/tonerdo/pose




回答5:


As @aqwert and @Felice wrote when using Typemock Isolator it's possible (and pretty easy) to mock Non-virtual methods without adding or changing any code, for example:

[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);
    }

as you can see the test i've created is similar to the test you tried to create.




回答6:


The only way to mock non virtual methods is to mock interface used to implement that class with non virtual methods. Below is the example.

public interface IEmployee
{
    DateTime GetDateofJoining(int id);
}

public class Employee
{
    public DateTime GetDateofJoining(int id)
    {
        return DateTime.Now;
    }
}

    public class Program
{
    static void Main(string[] args)
    {
        var employee = new Mock<IEmployee>();
        employee.Setup(x => x.GetDateofJoining(It.IsAny<int>())).Returns((int x) => DateTime.Now);

        Console.WriteLine(employee.Object.GetDateofJoining(1));
        Console.ReadLine();
    }
}


来源:https://stackoverflow.com/questions/11738102/how-to-mock-non-virtual-methods

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!