Używanie IoC do testów jednostkowych

97

Jak można używać kontenera IoC do testów jednostkowych? Czy warto zarządzać makietami w ogromnym rozwiązaniu (ponad 50 projektów) przy użyciu IoC? Jakieś doświadczenia? Jakieś biblioteki C #, które dobrze sprawdzają się przy używaniu go w testach jednostkowych?

crauscher
źródło
7
@Mark Seemann byłby zbyt pokorny, aby to wskazać, ale jeśli jesteś zainteresowany tym pytaniem, powinieneś przynajmniej zdawać sobie sprawę z AutoFixture
Ruben Bartelink
1
Jest dobra rozmowa o związku między DI a kpiną na Vimeo autorstwa Miguela Castro: vimeo.com/68390510
GregC,

Odpowiedzi:

131

Ogólnie rzecz biorąc, kontener DI nie powinien być konieczny do testowania jednostkowego, ponieważ testowanie jednostkowe polega na rozdzieleniu obowiązków.

Rozważ klasę, która używa funkcji Constructor Injection

public MyClass(IMyDependency dep) { }

W całej aplikacji może być ukryty ogromny wykres zależności IMyDependency, ale w teście jednostkowym spłaszczasz to wszystko do jednego podwójnego testu .

Możesz użyć dynamicznych makiet, takich jak Moq lub RhinoMocks, aby wygenerować Test Double, ale nie jest to wymagane.

var dep = new Mock<IMyDependency>().Object;
var sut = new MyClass(dep);

W niektórych przypadkach posiadanie kontenera z auto-mockowaniem może być przyjemne, ale nie trzeba używać tego samego kontenera DI, którego używa aplikacja produkcyjna.

Mark Seemann
źródło
13
... chyba że uzgodniony cel badania ma kontenera IoC jako zależność, twoje testy nie powinny ich potrzebować ... idziesz do usunięcia większości wykresu obiektu, kiedy wykonujesz swoje testy jednostkowe.
Anderson Imes
4
@Mark Seemann To ma sens ... Ale co z testami integracyjnymi? To znaczy, bawiłem się testami UI i stanąłem w obliczu sytuacji, w której musiałem udostępnić katalog główny kompozycji. Jakieś uwagi?
Arnis Lapsa
5
@Arnis L .: W przypadku testów integracyjnych jest to mniej ważne. Możesz zdecydować się na użycie kontenera DI do połączenia komponentów, ale jeśli tak, prawdopodobnie będziesz potrzebować innej konfiguracji kontenera niż w pełnej aplikacji - chyba że wykonasz test podskórny lub pełny test systemu, w takim przypadku możesz ponownie użyć konfiguracji aplikacji kontenera.
Mark Seemann
ref to msdn magazine Test Double: download.microsoft.com/download/3/A/7/...
M.Hassan
18

Jak można używać kontenera Ioc do testów jednostkowych?

IoC wymusi paradygmaty programowania, które sprawią, że testy jednostkowe w izolacji (tj. Przy użyciu makiet) będą łatwiejsze: użycie interfejsów, brak new (), żadnych singletonów ...

Ale używanie kontenera IoC do testowania nie jest tak naprawdę wymaganiem, po prostu zapewni pewne ułatwienia, np. Wstrzyknięcie makiet, ale możesz to zrobić ręcznie.

Czy warto zarządzać makietami w ogromnym rozwiązaniu (ponad 50 projektów) przy użyciu IoC?

Nie jestem pewien, co masz na myśli, mówiąc o zarządzaniu makietami za pomocą IoC. W każdym razie kontenery IoC mogą zwykle robić więcej niż tylko wprowadzanie makiet, jeśli chodzi o testowanie. A jeśli masz przyzwoitą obsługę IDE, która umożliwia refaktoryzację, dlaczego by jej nie użyć?

Jakieś doświadczenie?

Tak, w przypadku ogromnego rozwiązania potrzebujesz bardziej niż kiedykolwiek rozwiązania nie podatnego na błędy i niekorzystnego dla refaktoryzacji (tj. Poprzez bezpieczny dla typu kontener IoC lub dobre wsparcie IDE).

Pascal Thivent
źródło
17

W moich testach często używam kontenera IoC. To prawda, że ​​nie są to „testy jednostkowe” w czystym sensie. IMO Są bardziej BDDish i ułatwiają refaktoryzację. Testy mają na celu dać Ci pewność podczas refaktoryzacji. Źle napisane testy mogą być jak wlewanie cementu do kodu.

Rozważ następujące:

[TestFixture]
public class ImageGalleryFixture : ContainerWiredFixture
{
    [Test]
    public void Should_save_image()
    {
        container.ConfigureMockFor<IFileRepository>()
            .Setup(r => r.Create(It.IsAny<IFile>()))
            .Verifiable();

        AddToGallery(new RequestWithRealFile());

        container.VerifyMockFor<IFileRepository>();
    }

    private void AddToGallery(AddBusinessImage request)
    {
        container.Resolve<BusinessPublisher>().Consume(request);
    }
}

Podczas dodawania obrazu do galerii dzieje się kilka rzeczy. Obraz jest zmieniany, generowana jest miniatura, a pliki są przechowywane w AmazonS3. Używając kontenera, mogę łatwiej wyodrębnić tylko zachowanie, które chcę przetestować, które w tym przypadku jest stałą częścią.

Podczas korzystania z tej techniki przydaje się automatyczne mockowanie rozszerzenia kontenera: http://www.agileatwork.com/auto-mocking-unity-container-extension/

Mike Valenty
źródło
8
+1 dla frazy „jak wlewanie cementu do kodu”. Zacząłem go używać cały czas.
Andrew Shepherd
2

Używając kontenerów z możliwością rozwiązywania niezarejestrowanych / nieznanych usług, takich jak SimpleInjector , DryIoc (jego kopalnia) może zwracać makiety dla jeszcze nie zaimplementowanych interfejsów.

Oznacza to, że możesz rozpocząć programowanie od pierwszej prostej implementacji i jej wyimaginowanych zależności i zastępować je prawdziwymi w miarę postępów.

dadhi
źródło