问题
[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