Różne metody testowania
Najpierw określ, co robisz: testy jednostkowe lub testy integracyjne . Liczba warstw nie ma znaczenia dla testów jednostkowych, ponieważ najprawdopodobniej testowana jest tylko jedna klasa. Reszta wyśmiewasz. W przypadku testów integracji nieuniknione jest testowanie wielu warstw. Jeśli masz dobre testy jednostkowe, sztuczka polega na tym, aby testy integracyjne nie były zbyt skomplikowane.
Jeśli twoje testy jednostkowe są dobre, nie musisz powtarzać testowania wszystkich szczegółów podczas testowania integracji.
Warunki, których używamy, są nieco zależne od platformy, ale można je znaleźć na prawie wszystkich platformach testowych / programistycznych:
Przykładowa aplikacja
W zależności od technologii, której używasz, nazwy mogą się różnić, ale wykorzystam to jako przykład:
Jeśli masz prostą aplikację CRUD z modelem Product, ProductsController i widokiem indeksu, który generuje tabelę HTML z produktami:
Efektem końcowym aplikacji jest wyświetlenie tabeli HTML z listą wszystkich aktywnych produktów.
Testów jednostkowych
Model
Model, który możesz dość łatwo przetestować. Istnieją na to różne metody; używamy urządzeń. Myślę, że to właśnie nazywacie „fałszywymi zestawami danych”. Dlatego przed każdym uruchomieniem testu tworzymy tabelę i wstawiamy oryginalne dane. Większość platform ma na to metody. Na przykład w klasie testowej metoda setUp () uruchamiana przed każdym testem.
Następnie uruchamiamy nasz test, na przykład: produkty testGetAllActive .
Testujemy więc bezpośrednio do testowej bazy danych. Nie kpimy z źródła danych; sprawiamy, że zawsze jest tak samo. Dzięki temu możemy na przykład przetestować nową wersję bazy danych i pojawią się wszelkie problemy z zapytaniami.
W prawdziwym świecie nie zawsze możesz podążać w 100% za pojedynczą odpowiedzialnością . Jeśli chcesz to zrobić jeszcze lepiej, możesz użyć źródła danych, które wyśmiewasz. Dla nas (używamy ORM), który wydaje się testowaniem już istniejącej technologii. Również testy stają się znacznie bardziej złożone i tak naprawdę nie testują zapytań. Trzymamy to w ten sposób.
Zaszyfrowane dane są osobno przechowywane w urządzeniach. To urządzenie jest jak plik SQL z instrukcją tworzenia tabeli i wstawkami do rekordów, których używamy. Utrzymujemy je małe, chyba że istnieje rzeczywista potrzeba testowania z dużą ilością zapisów.
class ProductModel {
public function getAllActive() {
return $this->find('all', array('conditions' => array('active' => 1)));
}
}
Kontroler
Kontroler wymaga więcej pracy, ponieważ nie chcemy z nim testować modelu. Więc to, co robimy, to kpina z modelu. Oznacza to: Testujemy metodę: index (), która powinna zwrócić listę rekordów.
Wyśmiewamy więc metodę modelową getAllActive () i dodajemy do niej ustalone dane (na przykład dwa rekordy). Teraz testujemy dane, które kontroler wysyła do widoku i porównujemy, czy naprawdę odzyskamy te dwa rekordy.
function testProductIndexLoggedIn() {
$this->setLoggedIn();
$this->ProductsController->mock('ProductModel', 'index', function(return array(your records) ));
$result=$this->ProductsController->index();
$this->assertEquals(2, count($result['products']));
}
Wystarczy. Staramy się dodawać jak najmniej funkcji do kontrolera, ponieważ utrudnia to testowanie. Ale oczywiście zawsze jest w nim trochę kodu. Na przykład testujemy wymagania takie jak: Pokaż te dwa rekordy tylko wtedy, gdy jesteś zalogowany.
Tak więc kontroler potrzebuje normalnie jednej próbki i niewielkiej ilości zakodowanych danych. Dla systemu logowania może być inny. W naszym teście mamy do tego metodę pomocniczą: setLoggedIn (). Ułatwia to testowanie przy użyciu logowania lub bez logowania.
class ProductsController {
public function index() {
if($this->loggedIn()) {
$this->set('products', $this->ProductModel->getAllActive());
}
}
}
Widoki
Testowanie widoków jest trudne. Najpierw wyodrębniamy logikę, która się powtarza. Umieszczamy to w Pomocnikach i testujemy te klasy w ścisły sposób. Oczekujemy zawsze takiej samej wydajności. Na przykład: generujHtmlTableFromArray ().
Następnie mamy pewne widoki specyficzne dla projektu. Nie testujemy ich. Testowanie jednostkowe nie jest tak naprawdę pożądane. Trzymamy je do testów integracyjnych. Ponieważ wyodrębniliśmy dużą część kodu do widoków, mamy tutaj mniejsze ryzyko.
Jeśli zaczniesz testować te, prawdopodobnie będziesz musiał zmieniać testy za każdym razem, gdy zmieniasz fragment HTML, który nie jest przydatny w większości projektów.
echo $this->tableHelper->generateHtmlTableFromArray($products);
Testy integracyjne
W zależności od platformy możesz tutaj pracować z historiami użytkowników itp. Może to być strona internetowa Selenium lub inne porównywalne rozwiązania.
Ogólnie po prostu ładujemy bazę danych z urządzeniami i stwierdzamy, które dane powinny być dostępne. Do pełnego testowania integracji używamy ogólnie bardzo globalnych wymagań. Tak: Ustaw produkt jako aktywny, a następnie sprawdź, czy produkt stanie się dostępny.
Nie testujemy wszystkiego ponownie, na przykład, czy dostępne są odpowiednie pola. Tutaj testujemy większe wymagania. Ponieważ nie chcemy powielać naszych testów ze sterownika lub widoku. Jeśli coś jest naprawdę kluczową / podstawową częścią aplikacji lub ze względów bezpieczeństwa (sprawdź, czy hasło NIE jest dostępne), dodajemy je, aby upewnić się, że jest poprawne.
Zaszyfrowane dane są przechowywane w urządzeniach.
function testIntegrationProductIndexLoggedIn() {
$this->setLoggedIn();
$result=$this->request('products/index');
$expected='<table';
$this->assertContains($expected, $result);
// Some content from the fixture record
$expected='<td>Product 1 name</td>';
$this->assertContains($expected, $result);
}