Vraag Hoe kan ik Mock Objects gebruiken in mijn unit-tests en toch Code Coverage gebruiken?


Momenteel begin ik met het introduceren van het concept van Mock-objecten in mijn Unit Tests. In het bijzonder gebruik ik het Moq-framework. Echter, een van de dingen die ik heb gemerkt is dat plotseling de klassen die ik aan het testen ben met behulp van dit framework een codedekking van 0% laten zien.

Nu begrijp ik dat, aangezien ik alleen de klasse bespot, het de eigenlijke klasse zelf niet draait ... maar hoe schrijf ik deze tests en heb ik Code Coverage om nauwkeurige resultaten te retourneren? Moet ik één reeks tests schrijven die Mocks gebruiken en één set om de klasse rechtstreeks te instantiëren.

Misschien doe ik iets verkeerd zonder het me te realiseren?

Hier is een voorbeeld van hoe ik probeer om een ​​klasse genaamd "MyClass" te testen:

using Moq;
using NUnitFramework;

namespace MyNameSpace
{
    [TestFixture]
    public class MyClassTests
    {

        [Test]
        public void TestGetSomeString()
        {
            const string EXPECTED_STRING = "Some String!";

            Mock<MyClass> myMock = new Mock<MyClass>();
            myMock.Expect(m => m.GetSomeString()).Returns(EXPECTED_STRING);

            string someString = myMock.Object.GetSomeString();

            Assert.AreEqual(EXPECTED_STRING, someString);
            myMock.VerifyAll();

        }

    }

    public class MyClass
    {
        public virtual string GetSomeString()
        {
            return "Hello World!";
        }
    }
}

Weet iemand wat ik anders zou moeten doen?


12
2017-12-03 05:20


oorsprong


antwoorden:


U gebruikt uw mock-objecten niet correct. Wanneer je mock-objecten gebruikt, wilde je testen hoe je code met andere objecten samenwerkt zonder de echte objecten daadwerkelijk te gebruiken. Zie de onderstaande code:

using Moq;
using NUnitFramework;

namespace MyNameSpace
    {
        [TestFixture]
        public class MyClassTests
        {

            [Test]
            public void TestGetSomeString()
            {
                const string EXPECTED_STRING = "Some String!";

                Mock<IDependance> myMock = new Mock<IDependance>();
                myMock.Expect(m => m.GiveMeAString()).Returns("Hello World");

                MyClass myobject = new MyClass();

                string someString = myobject.GetSomeString(myMock.Object);

                Assert.AreEqual(EXPECTED_STRING, someString);
                myMock.VerifyAll();

            }

        }

        public class MyClass
        {

            public virtual string GetSomeString(IDependance objectThatITalkTo)
            {
                return objectThatITalkTo.GiveMeAString();
            }
        }

        public interface IDependance
        {
            string GiveMeAString();
        }
    }

Het ziet er niet naar uit dat het iets nuttigs doet wanneer je code gewoon een string teruggeeft zonder enige logica erachter.

De echte macht komt als jij GetSomeString() methode heeft enige logica toegepast die het resultaat van de uitvoerstring kan wijzigen afhankelijk van het rendement van de IDependdance  .GiveMeAString() methode, dan kunt u zien hoe uw methode omgaat met slechte gegevens die worden verzonden vanuit de IDependdance interface.

Zoiets als:

 public virtual string GetSomeString(IDependance objectThatITalkTo {
     if (objectThatITalkTo.GiveMeAString() == "Hello World")
     return "Hi";
 }

Als u deze regel in uw test hebt staan:

myMock.Expect(m => m.GiveMeAString()).Returns(null);

Wat zal er met je gebeuren GetSomeString() methode?


16
2017-12-03 05:41



Grote fout is spot met de Systeem onder test (SUT), je test iets anders. Je moet alleen SUT-afhankelijkheden bespotten.


7
2017-12-03 05:26



Ik zou aanraden om weg te blijven van het spotten van frameworks totdat je de interacties begrijpt die hier gaande zijn.

IMO het is beter om te leren met handmatig gecreëerde test doubles en daarna pas daarna over te stappen naar een spotcontext. Mijn redenering:

  1. Mocking-frameworks abstraheren wat er daadwerkelijk gebeurt; het is gemakkelijker om de interacties te begrijpen als u uw afhankelijkheden expliciet moet maken en vervolgens de tests in de foutopsporing moet volgen.

  2. Het is gemakkelijk om frameworks te misbruiken. Als u uw eigen rolt wanneer u aan het leren bent, begrijpt u eerder de verschillen tussen verschillende soorten testdubbelen. Als je meteen doorgaat naar een spotmodel, is het makkelijk om moppen te gebruiken als je stubs wilt en andersom - er is een groot verschil.

Zie het op deze manier: de klasse die getest wordt, is de focus. U maakt er een instantie van, roept de methoden op en stelt vervolgens dat het resultaat correct is. Als de klasse die wordt getest afhankelijkheden heeft (er is bijvoorbeeld iets vereist in de constructor), voldoet u aan die afhankelijkheden door A: echte klassen of B: testdubbelen te gebruiken.

De reden dat we testdubbelen gebruiken, is dat het de geteste klasse isoleert, wat betekent dat je de code op een meer gecontroleerde manier kunt gebruiken.

Bijv. als u een klasse hebt die een netwerkobject bevat, kunt u de foutafhandelingsroutines van de eigen klasse niet testen die dode verbindingen detecteren als u gedwongen bent om een ​​concreet netwerkverbindingsobject te gebruiken. In plaats daarvan injecteert u een nep-verbindingsobject en geeft u aan dat het een uitzondering moet genereren wanneer de methode "SendBytes" wordt aangeroepen.

D.w.z. In elke test worden de afhankelijkheden van de geteste klasse specifiek gemaakt om een ​​bepaald stuk code uit te oefenen.


2
2018-06-06 02:23



Dat is heel logisch. In wezen zeg je dat ik het volgende moet doen:

public class MyClass
{
    public virtual string GetSomeString(MyOtherClass moc)
    {
        return moc.ToString();
    }
}

.....

Mock<MyOtherClass> myMock = new Mock<MyOtherClass>();

MyClass mc = new MyClass();

string someString = mc.GetSomeString(myMock.Object);
Assert.AreEqual(EXPECTED_STRING, someString);

In wezen een instantiatie van de SUT en alleen het gebruiken van mocks voor de klassen die de SUT vereist?


0
2017-12-03 05:41