Oto jak chciałbym napisać jedną z kilku testów jednostkowych do takiego zakładu (z xUnit.net):
[Fact]
public void CreateReturnsInstanceWithCorrectParam1()
{
var sut = new FooFactory();
var expected = new object();
var actual = sut.Create(expected, new object());
var concrete = Assert.IsAssignableFrom<Foo>(actual);
Assert.Equal(expected, concrete.Object1);
}
Czy przerwać hermetyzacji? Tak i nie ... trochę. W enkapsulacji nie chodzi tylko o ukrywanie danych - co ważniejsze, jest to około protecting the invariants of objects.
Załóżmy, że Foo eksponuje tę publicznego API:
public class Foo : IFoo
{
public Foo(object param1, object param2);
public void MethodDefinedByInterface();
public object Object1 { get; }
}
Podczas gdy nieruchomość Object1
lekko naruszyć Law of Demeter, to nie bałagan z niezmienników klasy, ponieważ jest tylko do odczytu.
Ponadto nieruchomość Object1
jest częścią betonu klasy Foo - nie interfejs IFoo:
public interface IFoo
{
void MethodDefinedByInterface();
}
Kiedy zdajesz sobie sprawę, że w luźno API, concrete members are implementation details takie konkretne tylko do odczytu tylko obiekty bardzo mały wpływ na enkapsulację. Pomyśl o tym w ten sposób:
publiczna konstruktor Foo jest również częścią API betonu klasy Foo, więc po prostu sprawdzając publicznych API, dowiadujemy się, że param1
i param2
są częścią klasy. W pewnym sensie to już "przerywa enkapsulację", więc udostępnienie każdego parametru jako właściwości tylko do odczytu na konkretnej klasie niewiele się zmienia.
Dzięki tym właściwościom możemy teraz jednostce przetestować konstrukcyjny kształt klasy Foo zwróconej przez fabrykę.
Jest to znacznie łatwiejsze niż powtarzanie zestawu behawioralnych testów jednostkowych, które, jak możemy przyjąć, obejmują już konkretną klasę Foo. To prawie jak logiczny dowód:
- Z testów konkretnej klasy Foo wiemy, że poprawnie używa/współdziała z jej parametrami konstruktora.
- Z tych testów wiemy również, że parametr konstruktora jest wyświetlany jako właściwość tylko do odczytu.
- Z testu FooFactory wiemy, że zwraca instancję konkretnej klasy Foo.
- Ponadto, z testów metody Create wiemy, że jej parametry są poprawnie przekazywane do konstruktora Foo.
- Q.E.D.
Testy jednostkowe powinny zależeć od wymagań funkcjonalnych i oczekiwań względem badanego komponentu. Nie widzę żadnej wartości jednostki testującej tę klasę bez reszty kontekstu. – ivowiblo
@ivowiblo Myślę, że mylicie testy jednostkowe z testami BDD. Jeśli nie napiszesz testu dla tego urządzenia, to skąd wiesz, czy to działa? –
Wykonaj test jednostki, ale co będziesz testować? jakie jest oczekiwanie na tę jednostkę? Powiedziałem, że nie widzę wartości robienia testu jednostkowego dla tej klasy, nie wiedząc nic więcej. Przeprowadzanie testów jednostkowych z powodu przeprowadzania testów jednostkowych w ogóle nie ma sensu. Testowanie (jednostki, zachowania, pełne funkcjonalności, cokolwiek chcesz) powinno zawsze opierać się na oczekiwaniach i wymaganiach. Jeśli nie, to po prostu snobizm (jeśli to słowo istnieje). – ivowiblo