102 votes

Comment utiliser Moq pour simuler une méthode d'extension?

Je suis en train d'écrire un test qui repose sur les résultats d'une méthode d'extension, mais je ne veux pas d'un futur échec de cette méthode d'extension à jamais briser ce test. Se moquant de ce résultat semblait être le choix évident, mais Moq ne semble pas offrir un moyen de surcharger une méthode statique (une demande pour une extension de la méthode). Il y a une idée similaire avec Moq.Protégés et de Moq.Stub, mais ils ne semblent pas offrir quelque chose pour ce scénario. Ai-je raté quelque chose ou dois-je aller sur ce une manière différente?

Voici un exemple trivial qui échoue avec l'habituel "Invalide attente sur un non-substituables membre". C'est un mauvais exemple d'avoir besoin de se moquer d'une méthode d'extension, mais elle devrait faire.

public class SomeType {
    int Id { get; set; }
}

var ListMock = new Mock<List<SomeType>>();
ListMock.Expect(l => l.FirstOrDefault(st => st.Id == 5))
        .Returns(new SomeType { Id = 5 });

Comme pour toute TypeMock junkies qui pourrait me suggère d'utiliser un Isolateur à la place: j'apprécie l'effort fait qu'il ressemble à TypeMock pourrait faire le travail, les yeux bandés et en état d'ébriété, mais notre budget n'est pas en augmentant tout moment bientôt.

85voto

Mendelt Points 21583

Les méthodes d'extension ne sont que des méthodes statiques déguisées. Les frameworks moqueurs tels que Moq ou Rhinomocks ne peuvent créer que des occurrences fictives d'objets. Cela signifie qu'il n'est pas possible de se moquer de méthodes statiques.

40voto

informatorius Points 11

Si vous pouvez changer le code des méthodes d'extension, vous pouvez le coder comme ceci pour pouvoir tester:

 using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

public static class MyExtensions
{
    public static IMyImplementation Implementation = new MyImplementation();

    public static string MyMethod(this object obj)
    {
        return Implementation.MyMethod(obj);
    }
}

public interface IMyImplementation
{
    string MyMethod(object obj);
}

public class MyImplementation : IMyImplementation
{
    public string MyMethod(object obj)
    {
        return "Hello World!";
    }
}
 

Les méthodes d'extention ne constituent donc qu'un wrapper autour de l'interface d'implémentation.

(Vous pouvez utiliser uniquement la classe d'implémentation sans les méthodes d'extension, qui sont en quelque sorte un sucre syntaxique.)

Et vous pouvez simuler l'interface d'implémentation et la définir comme implémentation pour la classe d'extensions.

 public class MyClassUsingExtensions
{
    public string ReturnStringForObject(object obj)
    {
        return obj.MyMethod();
    }
}

[TestClass]
public class MyTests
{
    [TestMethod]
    public void MyTest()
    {
        // Given:
        //-------
        var mockMyImplementation = new Mock<IMyImplementation>();

        MyExtensions.Implementation = mockMyImplementation.Object;

        var myObject = new Object();
        var myClassUsingExtensions = new MyClassUsingExtensions();

        // When:
        //-------
        myClassUsingExtensions.ReturnStringForObject(myObject);

        //Then:
        //-------
        // This would fail because you cannot test for the extension method
        //mockMyImplementation.Verify(m => m.MyMethod());

        // This is success because you test for the mocked implementation interface
        mockMyImplementation.Verify(m => m.MyMethod(myObject));
    }
}
 

17voto

Mike Fielden Points 3469

Je sais que cette question n’est pas active depuis environ un an, mais Microsoft a publié un framework pour gérer exactement ce que l’on appelle Moles .

Voici quelques tutoriels:

DimeCasts.net Tutoriel de Nikolai Tillman

15voto

ranthonissen Points 772

J'ai créé une classe wrapper pour les méthodes d'extension que je devais me moquer.

 public static class MyExtensions
{
    public static string MyExtension<T>(this T obj)
    {
        return "Hello World!";
    }
}

public interface IExtensionMethodsWrapper
{
    string MyExtension<T>(T myObj);
}

public class ExtensionMethodsWrapper : IExtensionMethodsWrapper
{
    public string MyExtension<T>(T myObj)
    {
        return myObj.MyExtension();
    }
}
 

Ensuite, vous pouvez simuler les méthodes d'encapsulation dans vos tests et coder avec votre conteneur IOC.

14voto

kzu Points 1133

Si vous contrôlez la définition des méthodes d’extension (c’est-à-dire qu’elles ne font pas partie de celles de LINQ), il existe une autre alternative, expliquée à l’ adresse http://www.clariusconsulting.net/blogs/kzu/archive/2009/02/19/ Makingextensionmethodsamenabletomocking.aspx "Rendre les méthodes d’extension faciles à se moquer"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X