Jak testować prywatne metody z NUnit?

Zastanawiam się jak poprawnie używać NUnit. Najpierw stworzyłem osobny projekt testowy, który wykorzystuje mój główny projekt jako odniesienie. Ale w takim przypadku nie jestem w stanie przetestować prywatnych metod. Domyślam się, że muszę dołączyć mój kod testowy do mojego głównego kodu?! - To nie jest właściwy sposób. (Nie podoba mi się pomysł wysyłania kodu z testami w nim.)

Jak testować prywatne metody z NUnit?

Author: Alex Angas, 2008-10-30

12 answers

Ogólnie, testowanie jednostkowe odnosi się do publicznego interfejsu klasy, opierając się na teorii, że implementacja jest nieistotna, o ile wyniki są poprawne z punktu widzenia klienta.

Tak więc NUnit nie zapewnia żadnego mechanizmu do testowania członków niepublicznych.

 67
Author: harpo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-30 11:23:31

Powszechnym wzorcem pisania testów jednostkowych jest testowanie tylko metod publicznych.

Jeśli okaże się, że masz wiele prywatnych metod, które chcesz przetestować, zwykle jest to znak, że powinieneś refaktorować swój kod.

Byłoby błędem upublicznianie tych metod na klasie, w której obecnie mieszkają. To by złamało umowę, którą chcesz mieć na zajęciach.

Poprawne może być przeniesienie ich do klasy pomocniczej i upublicznienie ich tam. Ta klasa może nie być narażone przez API.

W ten sposób kod testowy nigdy nie jest mieszany z kodem publicznym.

Podobny problem to testowanie klas prywatnych ie. klasy, których nie eksportujesz ze swojego zestawu. W tym przypadku możesz jawnie uczynić swój zestaw kodu testowego przyjacielem zestawu kodu produkcyjnego za pomocą atrybutu InternalsVisibleTo.

 43
Author: morechilli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-30 11:43:56

Chociaż zgadzam się, że celem testów jednostkowych powinien być publiczny interfejs, uzyskujesz znacznie bardziej szczegółowe wrażenie kodu, jeśli przetestujesz również prywatne metody. Framework MS testing pozwala na to poprzez użycie PrivateObject i PrivateType, NUnit tego nie robi. To co robię zamiast tego to:

private MethodInfo GetMethod(string methodName)
{
    if (string.IsNullOrWhiteSpace(methodName))
        Assert.Fail("methodName cannot be null or whitespace");

    var method = this.objectUnderTest.GetType()
        .GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);

    if (method == null)
        Assert.Fail(string.Format("{0} method not found", methodName));

    return method;
}

W ten sposób nie musisz kompresować kapsułkowania na rzecz testowalności. Pamiętaj, że musisz zmodyfikować BindingFlags, jeśli chcesz przetestować prywatną statykę metody. Powyższy przykład to tylko na przykład metody.

 41
Author: user1039513,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-27 15:08:41

Możliwe jest przetestowanie prywatnych metod przez zadeklarowanie zestawu testowego jako zestawu znajomego zestawu docelowego, który testujesz. Zobacz poniższy link po szczegóły:

Http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx

Może to być przydatne, ponieważ w większości oddziela kod testowy od kodu produkcyjnego. Sam nigdy nie korzystałem z tej metody, ponieważ nigdy nie znalazłem jej potrzeby. Przypuszczam, że możesz go użyć do testowania ekstremalnych przypadków testowych, które po prostu nie można replikować w środowisku testowym, aby zobaczyć, jak Twój kod sobie z tym radzi.

Jak już zostało powiedziane, naprawdę nie powinieneś testować prywatnych metod. Ty bardziej niż likley chcesz refaktorować swój kod na mniejsze bloki konstrukcyjne. Jedną z porad, która może Ci pomóc, gdy przyjdziesz do refactor, jest próba zastanowienia się nad domeną, do której odnosi się Twój system, i zastanowienie się nad "prawdziwymi" obiektami, które zamieszkują tę domenę. Twoje obiekty/klasy w Twoim systemie powinny odnosić się bezpośrednio do rzeczywistego obiekt, który pozwoli wyizolować dokładne zachowanie, które obiekt powinien zawierać, a także ograniczyć obowiązki obiektów. Oznacza to, że refaktoryzujesz logicznie, a nie tylko po to, aby umożliwić testowanie określonej metody; będziesz w stanie przetestować zachowanie obiektów.

Jeśli nadal czujesz potrzebę testowania wewnętrznego, możesz również rozważyć wyśmiewanie się w testach, ponieważ chcesz skupić się na jednym kawałku kodu. Wyśmiewanie jest tam, gdzie ty wstrzyknąć do niego zależności obiektów, ale wtryskiwane obiekty nie są obiektami "rzeczywistymi" lub produkcyjnymi. Są to atrapy obiektów z zakodowanym na twardo zachowaniem, ułatwiającym izolowanie błędów behawioralnych. Nosorożec.Mocks jest popularnym darmowym frameworkiem, który zasadniczo napisze obiekty za Ciebie. TypeMock.NET (produkt komercyjny z dostępną wersją społecznościową) jest potężniejszym frameworkiem, który może naśladować obiekty CLR. Bardzo przydatny do szydzenia z SqlConnection/SqlCommand i Datatable klasy na przykład podczas testowania aplikacji bazodanowej.

Mam nadzieję, że ta odpowiedź da ci nieco więcej informacji, aby poinformować Cię o testach jednostkowych w ogóle i pomóc ci uzyskać lepsze wyniki z testów jednostkowych.

 21
Author: Dafydd Giddins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-22 12:55:05

Głównym celem testów jednostkowych jest przetestowanie publicznych metod danej klasy. Te metody publiczne będą wykorzystywać te metody prywatne. Testowanie jednostkowe przetestuje zachowanie tego, co jest publicznie dostępne.

 4
Author: Maxime Rouiller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-30 11:25:11

Jestem za posiadaniem możliwości testowania prywatnych metod. Po uruchomieniu xUnit był przeznaczony do testowania funkcjonalności po napisaniu kodu. Do tego celu wystarczy przetestowanie interfejsu.

Testy jednostkowe ewoluowały w rozwój oparty na testach. Posiadanie możliwości testowania wszystkich metod jest przydatne dla tej aplikacji.

 4
Author: Mark Glass,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-16 19:47:15

To pytanie jest w zaawansowanym wieku, ale pomyślałem, że podzielę się moim sposobem na zrobienie tego.

Zasadniczo, mam wszystkie moje klasy testów jednostkowych w assembly, które testują w przestrzeni nazw 'UnitTest' poniżej 'default' dla tego assembly - każdy plik testowy jest zawinięty w:

#if DEBUG

...test code...

#endif

Blok, A to wszystko oznacza, że a) nie jest dystrybuowany w wydaniu i B) mogę użyć internal/Friend deklaracje poziomu bez skoków obręczy.

Druga rzecz, która oferuje, bardziej istotne do tego pytania, jest użycie klas partial, które mogą być użyte do utworzenia proxy do testowania prywatnych metod, więc na przykład do testowania czegoś w rodzaju prywatnej metody, która zwraca wartość całkowitą:

public partial class TheClassBeingTested
{
    private int TheMethodToBeTested() { return -1; }
}

W klasach głównych zespołu i klasie testowej:

#if DEBUG

using NUnit.Framework;

public partial class TheClassBeingTested
{
    internal int NUnit_TheMethodToBeTested()
    {
        return TheMethodToBeTested();
    }
}

[TestFixture]
public class ClassTests
{
    [Test]
    public void TestMethod()
    {
        var tc = new TheClassBeingTested();
        Assert.That(tc.NUnit_TheMethodToBeTested(), Is.EqualTo(-1));
    }
}

#endif

Oczywiście, musisz upewnić się, że nie używasz tej metody podczas tworzenia, chociaż Release build wkrótce wskaże nieumyślne wywołanie tej metody, jeśli to zrobisz.

 4
Author: Stuart Wood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-19 07:59:14

Przepraszamy, jeśli to nie odpowiada na pytanie, ale rozwiązania takie jak używanie reflection, #if #endif lub upublicznianie prywatnych metod nie rozwiązują problemu. Może być kilka powodów, dla których metody prywatne nie są widoczne... co jeśli to kod produkcyjny, a zespół retrospektywnie pisze testy jednostkowe na przykład.

Dla projektu, nad którym pracuję tylko MSTest (niestety) wydaje się mieć sposób, używając accesorów, do jednostkowego testowania prywatnych metod.

 3
Author: Ritesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-02 18:13:06

Nie testujesz prywatnych funkcji. Istnieją sposoby, aby użyć refleksji, aby dostać się do prywatnych metod i właściwości. Ale to nie jest naprawdę łatwe i zdecydowanie odradzam tę praktykę.

Po prostu nie powinieneś testować niczego, co nie jest publiczne.

Jeśli masz jakieś wewnętrzne metody i właściwości, powinieneś rozważyć zmianę tego na publiczne lub wysłanie testów za pomocą aplikacji(coś, co nie jest dla mnie problemem).

Jeśli klient jest w stanie uruchomić Test-Suite i zobaczyć, że kod dostarczony jest rzeczywiście "działa", nie widzę tego jako problem(tak długo, jak nie oddać swój IP przez to). To, co dołączam do każdego wydania, to raporty z testów i raporty dotyczące kodu.

 2
Author: Tigraine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-30 11:33:32

Możesz uczynić swoje metody chronione wewnętrznie, a następnie za pomocą assembly: InternalVisibleTo("NAMESPACE") do Twojej testowej przestrzeni nazw.

Stąd, nie! Nie można uzyskać dostępu do metod prywatnych, ale jest to obejście.

 1
Author: Furgalicious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-31 18:12:08

W teorii testów jednostkowych należy badać tylko kontrakt. tj. tylko publicznych członków klasy. Ale w praktyce deweloper zwykle chce przetestować wewnętrzne członków do. - i nie jest źle. Tak, jest to sprzeczne z teorią, ale w praktyce czasami może być przydatne.

Więc jeśli naprawdę chcesz przetestować wewnętrzne członków można użyć jednego z tych podejść:

    Upublicznij swojego członka. W wielu książkach autorzy sugerują to podejście proste
  1. możesz uczynić z siebie członków wewnętrzne i dodać InternalVisibleTo do assebly
  2. możesz chronić członków klasy i dziedziczyć klasę testową z twojej klasy testowej.

Przykład kodu (pseudo kod):

public class SomeClass
{
    protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{

    protected void SomeMethod2() {}
    [Test]
    public void SomeMethodTest() { SomeMethod2(); }
}
 1
Author: burzhuy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-27 12:35:49

Chciałbym, aby pakiet metod prywatnych był widoczny. W ten sposób zachowujesz prywatność, a jednocześnie możesz testować te metody. Nie zgadzam się z tym, że tylko publiczne interfejsy powinny być testowane. Często w metodach prywatnych znajduje się naprawdę krytyczny kod, który nie może być poprawnie przetestowany tylko przez zewnętrzne interfejsy.

Więc to naprawdę sprowadza się do tego, czy zależy Ci bardziej na poprawnym kodzie lub ukrywaniu informacji. Powiedziałbym, że pakiet widoczność jest dobrym kompromisem, ponieważ aby uzyskać dostęp do tych metod, ktoś musiałby umieścić swoją klasę w Twoim pakiecie. To naprawdę powinno skłonić ich do zastanowienia się dwa razy, czy jest to naprawdę mądra rzecz do zrobienia.

Jestem facetem Java btw, więc pakiet visiblilty może być nazywany coś zupełnie innego w C#. Wystarczy powiedzieć, że dwie klasy muszą być w tej samej przestrzeni nazw, aby uzyskać dostęp do tych metod.

 0
Author: Fylke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-30 11:55:17