web-dev-qa-db-fra.com

Comment se moquer des méthodes non virtuelles?

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

Le EmailService.SendEmail la méthode doit être virtuelle pour se moquer d'elle. Existe-t-il un moyen de se moquer des méthodes non virtuelles?

32
hbmaam

Moq ne peut pas se moquer des méthodes non virtuelles sur les classes. Soit utiliser d'autres frameworks de mocking tels que Type mock Isolator qui tisse réellement IL dans votre Assembly ou placez une interface sur EmailService et moquez-le.

22
aqwert

Se moquer des méthodes non virtuelles implique l'utilisation d'une API de profileur de bas niveau. Pour le moment, je pense que les seules options disponibles sont:

les deux sont commerciaux, même si JustMock a une édition lite, les méthodes non virtuelles moqueuses sont disponibles uniquement avec la version commerciale. Comme indiqué dans les commentaires, il y a quelque chose de la recherche Microsoft, dans le projet Pex et Moles

8
Felice Pollano

L'alternative à l'utilisation de méthodes virtuelles pour se moquer est d'utiliser des interfaces. De cette façon, vous pouvez simuler une dépendance entière.

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

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

Vous pouvez maintenant créer des simulations de l'interface IEmailService pour vous permettre de simuler n'importe laquelle de ses méthodes. Bien sûr, vous devrez changer les types de variables contenant EmailService objets en IEmailService le cas échéant.

6
Alexander R

Utilisez pose. Vous permet de remplacer toute méthode, y compris statique ou non virtuelle. Projet assez nouveau, mais entièrement open source MIT license. https://github.com/tonerdo/pose

4
James Reategui

Comme @aqwert et @Felice l'ont écrit lors de l'utilisation de Typemock Isolator , il est possible (et assez facile) de se moquer des méthodes non virtuelles sans ajouter ou modifier de code, par exemple:

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

comme vous pouvez le voir, le test que j'ai créé est similaire au test que vous avez essayé de créer.

2
Sam

La seule façon de simuler des méthodes non virtuelles est de simuler l'interface utilisée pour implémenter cette classe avec des méthodes non virtuelles. Voici l'exemple.

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();
    }
}
0
Rakesh Raut