web-dev-qa-db-fra.com

Se moquer d'une méthode de test

Essayer de se moquer d'une méthode qui est appelée dans une autre méthode.

public virtual bool hello(string name, int age)
{

    string lastName = GetLastName();
}

 public virtual string GetLastName() 
    {
        return "xxx"; 
    }

 Mock<program> name= new Mock<program>();
 name.Setup(x => x.GetLastName()).Returns("qqq");

Je veux que la méthode GetLastName renvoie toujours "qqq".

9
codeislife

Cela devrait fonctionner, en supposant que ce sont les implémentations de la méthode complète

public class MyProgram
{

    public bool hello(string name, int age)
    {
        string lastName = GetLastName();

        return string.Format("hello {0}", lastName);
    }

    public virtual string GetLastName() 
    {
        return "xxx"; 
    }
}

public class MyProgramTests
{

    [TestMethod]
    public void MyTest()
    {

        string stringToReturn = "qqq";
        Mock<MyProgram> name = new Mock<MyProgram>();
        name.CallBase = true;
        name.Setup(x => x.GetLastName()).Returns(stringToReturn );

        var results = name.Object.hello(It.IsAny<string>(), It.IsAny<int>());

        string expected = string.Format("hello {0}", results);

        Assert.AreEqual(expected, results);
    }
}

Je ne suis toujours pas tout à fait à la suite de votre commentaire:

Que signifie vraiment le paramètre de Mock Que devrait-il être ?? être? excusez-moi, je ne comprends pas très bien la syntaxe. Pour clarifier, mock signifie que lorsque je mets des points d'arrêt dans mon code, les points d'arrêt doivent ignorer les méthodes que je moque. Ai-je raison?

Mock<T> Vous permet de vous moquer d'un type de T - T étant un indicateur générique, ce qui signifie également à peu près tout ce qui est une classe. Dans le traditionnel, vous vous moqueriez d'une interface, pas d'une réelle class, mais dans l'exemple ci-dessus, nous nous moquons d'une classe. Pour l'exemple de test unitaire publié, le but du test unitaire est de tester l'implémentation de hello(string, int). Nous savons que hello(string, int) s'appuie sur une autre méthode de cette classe appelée GetLastName(). L'implémentation de GetLastName(), bien qu'importante, n'est pas importante pour la portée des tests unitaires hello(string, int). Pour cette raison, nous nous moquons de l'appel et de son retour - afin de tester la fonctionnalité de hello(string, int) sans avoir à se soucier de l'implémentation de sa dépendance.

J'ai entouré ce qui précède de noms de classe réels pour, espérons-le, rendre plus évident que nous nous moquons de la classe MyProgram et fournissons une nouvelle implémentation (mock) de GetLastName()

Merci d'avoir répondu. Que faire si je veux tester une méthode qui appelle une autre méthode qui appelle une autre méthode? Par exemple. Et si la méthode Bonjour appelait une autre méthode?

Le même principe s'applique, lorsque vous construisez vos tests unitaires (en supposant qu'ils sont unit tests, et non l'intégration tests ou autres, vous voulez toujours vous concentrer sur la méthode publique de test un. Quelle est la différence entre les tests unitaires et les tests d'intégration?

public class Foo
{

    public string Bar()
    {
        return string.Format("{0}Bar", Baz(5));;
    }

    public virtual string Baz(int someNumber)
    {
        return string.Format("{0}Baz", DoStuff(someNumber).ToString());
    }

    public virtual int DoStuff(int someNumber)
    {
        return someNumber+1;
    }

}

Si nous testons les unités Bar() nous ne nous soucions pas de l'implémentation de Baz(int) ou pire encore DoStuff(int). Remarque nous ne nous soucions pas de l'implémentation, nous do attention à ce qu'ils renvoient des valeurs. Du point de vue de Bar(), la seule chose importante est que Baz(int) renvoie une chaîne. Quelle chaîne? Peu importe le test unitaire de Bar().

Exemple de test pour Bar():

[TestMethod]
public void Bar_ReturnsBazValueWithBarAppended
{
    // Arrange
    string testBazReturn = "test";
    Mock<Foo> mock = new Mock<Foo>();
    mock.CallBase = true;
    mock
        .Setup(s => s.Baz(It.IsAny<int>())
        .Returns(testBazReturn);

    // Act
    var results = mock.Object.Bar();

    // Assert
    Assert.AreEqual(string.Format("{0}{1}", testBazReturn, "Bar"), results);
    mock.Verify(v => v.Baz(It.IsAny<int>())); // Verifies that Baz was called
}

Remarquez ci-dessus que nos implémentations réelles de Baz(int) et DoStuff(int) n'ont pas d'importance, car nous ignorons l'implémentation réelle de Baz(int) et DoStuff(int) n'entre même pas en jeu.

Maintenant, si nous devions tester Baz(int) nous suivons simplement la même mentalité:

[TestMethod]
public void Baz_ReturnsDoStuffValueWithBazAppended
{
    // Arrange
    int testDoStuffReturn = 1;
    Mock<Foo> mock = new Mock<Foo>();
    mock.CallBase = true;
    mock
        .Setup(s => s.DoStuff(It.IsAny<int>())
        .Returns(testDoStuffReturn);

    // Act
    var results = mock.Object.Baz(5);

    // Assert
    Assert.AreEqual(string.Format("{0}{1}", results, "Baz"), results); // Validates the result
    mock.Verify(v => v.DoStuff(It.IsAny<int>())); // Verifies that DoStuff was called
}

Dans ce qui précède, maintenant que nous testons les unités Baz(int), nous ne nous soucions pas de Bar(), et la seule chose qui nous intéresse dans DoStuff(int) est que il renvoie une valeur (mais pas comment il arrive à cette valeur.)

Et enfin DoStuff(int):

[TestMethod]
public void DoStuff_ReturnsParameterPlusOne()
{
    // Arrange
    Foo foo = new Foo();
    int passed = 1;
    int expected = passed + 1;

    // Act
    var results = foo.DoStuff(passed);

    // Assert
    Assert.AreEqual(expected, results);
}
9
Kritner