Niedawno opublikowałem posta o tym, jak nie należy pisać testów jednostkowych. Przytoczony przykład powodował bezsensowną duplikację kodu w aplikacji i testach.
Dzisiaj bardzo krótka demonstracja tego, jak można zastosować atrybut ValuesAttribute z NUnit 2.5 do wygenerowania testów dla więcej niż jednej wartości naraz. Testować będziemy klasę, która oblicza 22%-ową stawkę podatku VAT. Jej implementacja jest oczywiście banalna:
1: public class VatCalculator 2: { 3: public double Calculate(double netto) 4: { 5: if (netto < 0) 6: throw new ArgumentException(); 7: 8: return netto * 0.22; 9: } 10: }
Testów też nie można nazwać skomplikowanymi:
Zobaczcie jak za pomocą jednej deklaracji testu można uzyskać dość szczegółowe obłożenie testowanej metody różnymi wartościami! Co więcej, atrybut ValueSourceAttribute pozwala na dynamiczne dostarczanie takich wartości do testu.
Kolejnym aspektem, na który warto zwrócić uwagę, jest SequentialAttribute. Gdybym go w tym miejscu nie zastosował, zamiast niego nUnit wykorzystałby CombinatorialAttribute i wygenerował testy dla każdej możliwej pary wartości: [3562.5, 783.75], [3562.5, 0] i [0, 783.75]. A w tym przypadku jest to oczywiście niepożądane.
Uwaga kolejna dotycząca obsługi wyjątków. Jak można zauważyć, wolę konstrukcję Assert.Throws niż atrybut ExpectedException. Powody są dwa: 1) moim zdaniem lepiej wyraża ona intencje twórcy testu; 2) wspomniany atrybut jest niepoprawnie interpretowany przez niektóre narzędzia uruchamiające testy (w tym niestety test-runner z Resharpera).
I uwaga ostatnia: wszystko pięknie i ładnie, ale niestety “uruchamiacz” Resharperowy, którego używam na co dzień, nie potrafi poprawnie rozpoznać testu z omawianymi konstrukcjami… i je po prostu ignoruje. Na szczęście w wersji 5.0 się to zmieni (R# JIRA).