[C#] Class-Under-Test mocken met private methods

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Aphelion
  • Registratie: Januari 2002
  • Laatst online: 18:05
Ik heb een vraag over het onderstaande probleem:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class OriginalSample
{
    public bool Foo(ISomeEntity entity)
    {
        return entity.IsThatSo ? entity.IsThatSo : Bar(entity);
    }

    public bool Bar(ISomeEntity entity)
    {
        return entity.IsThatAsWell;
    }
}

[TestClass]
public class OriginalSampleTest
{
    [TestMethod]
    public void Foo_EntityWithSo_ReturnsTrue
    {
        // Arrange
        Mock<ISomeEntity> someEntityMock = new Mock<ISomeEntity>();
        mock.SetupGet(m => m.IsThatSo).Returns( false );
        mock.SetupGet(m => m.IsThatAsWell).Returns( true );

        // Act
        private bool result = _OriginalSample.Foo( someEntityMock.Object );

        // Assert
        Assert.IsTrue(result);
    }
}


Ik zoek een manier om 'Foo' te testen zonder dat de 'Bar' method geraakt wordt.

Ik ben gekomen tot de onderstaande oplossing. Het nadeel is echter dat ik een interface nodig heb en mijzelf moet meegeven in elke method. Deze oplossing bevalt mij niet.

Heeft iemand suggesties hoe ik dit probleem het beste kan omzeilen?

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public interface INewSample
{
    bool Foo(ISomeEntity entity, INewSample sample);
    bool Bar(ISomeEntity entity);
}

public class NewSample : INewSample
{
    public bool Foo(ISomeEntity entity, INewSample sample)
    {
        return entity.IsThatSo ? entity.IsThatSo : sample.Bar(entity);
    }

    public bool Bar(ISomeEntity entity)
    {
        return entity.IsThatAsWell;
    }
}

[TestClass]
public class NewSampleTest
{
    [TestMethod]
    public void Foo_EntityWithSo_ReturnsTrue
    {
        // Arrange
        Mock<ISomeEntity> someEntityMock = new Mock<ISomeEntity>();
        mock.SetupGet(m => m.IsThatSo).Returns( false );

        Mock<INewSample> sampleMock = new Mock<INewSample>();
        sampleMock.Setup(m => m.Bar).Returns(false).Verify();

        // Act
        private bool result = _OriginalSample.Foo( someEntityMock.Object, sampleMock.Object );

        // Assert (that the logic tried to use the 'bar' method
        sampleMock.Verify();
    }
}

Feeling lonely and content at the same time, I believe, is a rare kind of happiness


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Ik snap niet wat je hiermee wilt bereiken.

Je wilt toch gewoon testen of een class voldoet aan een contract? Je wilt toch juist niet weten hoe een class/method iets intern oplost?

Kun je uitleggen waarom je dit wilt doen?

Overigens staat er ook nog "met private methods" in je subject, die zie ik in het voorbeeld niet terug. Foutje of is dit onderdeel van de vraag?

[ Voor 26% gewijzigd door Herko_ter_Horst op 29-05-2012 13:40 ]

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • Aphelion
  • Registratie: Januari 2002
  • Laatst online: 18:05
Herko_ter_Horst schreef op dinsdag 29 mei 2012 @ 13:35:
Ik snap niet wat je hiermee wilt bereiken.

Je wilt toch gewoon testen of een class voldoet aan een contract? Je wilt toch juist niet weten hoe een class/method iets intern oplost?

Kun je uitleggen waarom je dit wilt doen?

Overigens staat er ook nog "met private methods" in je subject, die zie ik in het voorbeeld niet terug. Foutje of is dit onderdeel van de vraag?
Goed punt. Ik bedoel hiermee aan te geven dat de methods andere methods op diezelfde class-under-test aanroepen. De reden dat ik dit wil is omdat het design dat moet worden getest in de functie Foo() zowel business logic als aanroepen van andere functies veroorzaakt.

De reden dat ik dat wil voorkomen is omdat ik ik anders ook stubs moet maken die benodigd zijn voor de onderliggende Bar() methods terwijl ik alleen de business logic in Foo wil testen.

Overigens is het een mogelijkheid om de method te scheiden zodat eerst de logic kan worden getest, en daarna andere methods worden aangeroepen. Helaas is dit niet altijd mogelijk :)

[ Voor 8% gewijzigd door Aphelion op 29-05-2012 14:32 ]

Feeling lonely and content at the same time, I believe, is a rare kind of happiness


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Je wilt je test harness toch niet zo strak koppelen aan de details van je implementatie? Als de implementatie van Foo() gebruik maakt van Bar() dan wil je toch ook dat de methode correct werkt? Bar() is in deze implementatie toch gewoon onderdeel van de business logic van Foo()? Je wilt toch dat als iemand iets foutief verandert in de de implementatie van Bar() dat invloed heeft op Foo(), je test harness dat rapporteert (los van hoe Bar() zich op zichzelf gedraagt, wat uiteraard ook getest wordt)?

Lijkt me dat als je een object dat aan een bepaalde interface voldoet meegeeft aan een methode, dat je dan die hele interface moet mocken in je test. Tenzij je zeker weet dat een methode nooit aangeroepen kan/mag worden door een bepaalde class/method - en dan moet je je afvragen waarom die methode dan op die interface zit.

[ Voor 14% gewijzigd door Herko_ter_Horst op 29-05-2012 15:33 ]

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • SaphuA
  • Registratie: September 2005
  • Laatst online: 10-09 22:00
.

[ Voor 99% gewijzigd door SaphuA op 31-01-2022 15:24 ]


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
SaphuA schreef op woensdag 30 mei 2012 @ 15:33:
Je zou naar moles kunnen kijken. http://research.microsoft.com/en-us/projects/moles/

Dosclaimer:
Ik ben er zelf geen fan van, maar voor simpele unit tests in een klein project werkt dit prima. MS werkt overigens aan een nieuwe versie, onder een andere naam, met dezelfde voor-/nadelen, maar daar moet je even voor zoeken.
Misschien had je even door moeten lezen op diezelfde pagina: Moles is opgevolgd door het Fakes framework in VS 11. Maar voor zover ik het begrijp zit het probleem helemaal niet in het mock framework.

Tenzij jij kunt aangeven hoe het probleem van de TS wordt opgelost door dit framework te gebruiken?

[ Voor 18% gewijzigd door Herko_ter_Horst op 30-05-2012 15:56 ]

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • SaphuA
  • Registratie: September 2005
  • Laatst online: 10-09 22:00
.

[ Voor 103% gewijzigd door SaphuA op 31-01-2022 15:23 ]


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Los van of je een method in de class-under-test wilt mocken (volgens mij niet), is dat inderdaad iets wat kan met Moles? Dus niet het mocken van een externe class, maar van een method in de class die je aan het testen bent?

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • Aphelion
  • Registratie: Januari 2002
  • Laatst online: 18:05
Ik heb uiteindelijk besloten door een method toe te voegen die logica bevat die ik wil testen. Vervolgens heb ik een private method die de verschillende logic methods aanroept. Die hoeft verder niet getest te worden, want dat gaat wel blijken uit mijn integratie. En anders zou die test ook alleen bestaan uit, wordt method x tot y aangeroepen. Dit lijkt mij het moment dat ik stop met code coverage.

Los van dat, ben ik nu ook benieuwd of ik inderdaad, indien je het echt wilt, met moles een method in de class-under-test kan mocken.

Feeling lonely and content at the same time, I believe, is a rare kind of happiness

Pagina: 1