Posts tagged ‘testing’

Against Unit Tests

2012-02-26 21:23

When discussing the topic of unit testing and methodologies they might entail (mostly TDD, i.e. Test-Driven Development), I noticed a curious imbalance in the number and strength of arguments pro and contra. The latter are few and far between, up to the point of ridiculous scarcity when googling “arguments against TDD” is equally likely to yield stories from both sides of the fence. That’s pretty telling. Is it so that TDD in general and unit tests in particular are just the best thing ever, because there is an industry-wide consensus about them?…

I wouldn’t be so sure. All this unequivocal acknowledgement looks suspiciously similar to many other trends and fashions that were (or still are) sweeping through the IT domain, receding only when the alternative approach gains enough traction.


O RLY?

Take OOP, for example. Back in the 90s and around 2000, you would hear all kinds of praise for the object-oriented methodology: how natural it is, how it helps to model problems in intuitive way, how flexible and useful its abstractions are. Critics’ camp existed, of course, but they were small, scattered and not taken very seriously. Objects and classes were reigning supreme.

Compare this to present day, when OOP is taking blows from almost every direction. On one hand, it is rejected on performance basis, as the unknown factors of virtual method’s call are seen as a liability. On the other hand, its abstraction patterns are considered baroque, overblown and outdated, unfit for modern computing challenges – most notably concurrency and asynchronism.

Could it be that approaches emphasizing the utmost importance of unit tests are following the same route? Given the pretty much universal praise they are receiving, it’s not unimaginable. In this context, providing some reasonable counterarguments seems like a good thing: if we let some air out of this balloon, we may prevent it from popping later on.

Incidentally, this is a service for TDD/unit testing that I’m glad to provide ;-) So in the rest of this post, I’m going to discuss some of their potential drawbacks, hopefully helping to even-out the playing field. Ultimately, this should always lead to better software engineering practices, and better software.

Tags: , , ,
Author: Xion, posted under Programming, Thoughts » 3 comments

Odpalanie klasy

2010-08-31 12:09

Niskopoziomowe, wewnętrzne klasy logiki mają tę wadę (jeśli można to tak nazwać…), iż są właśnie niskopoziomowe i wewnętrzne – a przez to trudne do testowania w powiązaniu z całą aplikacją. Między nimi a interfejsem może znajdować się wiele warstw, które utrudniają debugowanie.
To sprawia, że przydatne stają się testy jednostkowe (unit tests). Do ich tworzenia i uruchamiania potrzeba jednak odpowiednich frameworków. Na szczęście te są już dostępne dla niemal każdego sensownego języka programowania i nierzadko są wręcz częścią jego lub jego środowiska.
Nie zawsze jednak tak było. Alternatywą dla ręcznego tworzenia specjalnych aplikacji przeznaczonych wyłącznie do testowania klas były (i właściwie nadal są) interesujące mechanizmy “uruchamiania klas” jako takich, które oferują niektóre języki programowania.

Dotyczy to przede wszystkim – jeśli nie wyłącznie – tych spośród nich, w których koncepcja programu czy aplikacji nie jest wyraźnie zakreślona. Coś jakiego jak entry point (“punkt wejścia”), od którego zaczyna się wykonywanie kodu, musi jednak istnieć i trzeba mieć jakiś sposób na jego określenie. Jeżeli zamiast aplikacji mamy tylko mniej lub bardziej luźny zbiór klas, to siłą rzeczy musi się on znajdować w którejś z nich.
A jeśli znajduje się w jednej, to czemu nie dodać go też do innych – także tych, które z założenia nie mają pojęcia o interakcji z użytkownikiem? Tworzymy w ten sposób pewnego rodzaju back-end, a owe dodatkowe punkty wejścia mogą posłużyć do testów. Oto prosty przykład w języku Java:
public class Sumator
{
private int sum = 0;
public void add(int x) { sum += x; }
public int getSum() { return sum; }

// testowy punkt wejścia
public static void main(String[] args) {
int n = args.length > 1 ? Integer.parseInt(args[1]) : 100;

Sumator s = new Sumator();
for (int i = 1; i <= n; ++i) s.add(i); System.out.println ("Spodziewana suma: " + (n * (n + 1) / 2)); System.out.println ("Otrzymana suma: " + s.getSum()); } }[/java] Statyczna metoda main to w Javie sposób na określenie punktu wejścia. Typowym miejscem dla niego jest główna klasa aplikacji, względnie całkiem osobna klasa przeznaczona do zarządzania samym uruchamianiem programu. Tutaj umieszczamy metodę main w klasie logiki (bardzo zaawansowanej zresztą ;-]), przez co możemy “odpalić” samą tę klasę i wykonać jakiś kod testujący jej funkcjonalność.

Z popularnych języków mających taki feature można jeszcze wspomnieć Pythona. W nim obiektowość nie jest obowiązkowa, więc to skrypt (plik .py) jest podstawową jednostką kodu, którą można uruchamiać:

  1. import sys
  2.  
  3. class Sumator:
  4.     def __init__(self): self.sum = 0
  5.     def add(self, x): self.sum += x
  6.  
  7. if __name__ == "__main__":
  8.     n = int(sys.argv[1]) if len(sys.argv) > 1 else 100
  9.     s = Sumator()
  10.     for i in range(1, n+1): s.add(i)
  11.     print "Spodziewana suma: ", (n * (n + 1) / 2)
  12.     print "Otrzymana suma: ", s.sum

Daje się w nim też umieścić “swobodny” kod, co na pierwszy rzut oka wydaje się dobrym miejscem na instrukcje testowe. Trzeba tylko otoczyć je pokazanym wyżej ifem, aby były one uruchamiane wyłącznie przy wywoływaniu skryptu z wiersza poleceń, nie zaś przy imporcie zawartego w nim kodu (instrukcją import).

Tags: , , , ,
Author: Xion, posted under Programming » Comments Off on Odpalanie klasy

O testach jednostkowych

2008-03-19 22:06

Kod skompilowany nie musi być kodem działającym poprawnie – tę prawidłowość zna każdy programista. Z drugiej jednak strony dogłębne przetestowanie programu jako całości to proces żmudny, trudny, niepokojący i obarczony sporym ryzykiem niepowodzenia. A przy tym oczywiście konieczny. Można go jednak nieco usprawnić poprzez ograniczenie możliwości występowania błędów w niektórych częściach programu – takich, które wcześniej potraktujemy testami jednostkowymi (unit tests).

Ten rodzaj testów w skrócie polega na tym, aby każdy napisany element kodu – co zależnie od języka i sposobu programowania może oznaczać np. funkcję lub klasę – opatrzyć jedną lub kilkoma procedurami testującymi. Mają one na celu sprawdzanie, czy ów element robi dokładnie to, co założyliśmy, poprzez użycie go “na zewnątrz”, w innym kodzie. Innymi słowy, taka procedura testowa ma na celu uruchomienie funkcjonalności jakiejś klasy/funkcji/itp. i sprawdzenie, czy rezultaty jej działania są zgodne z oczekiwanymi.
Takie procedury można pisać po zakończeniu implementacji testowanego elementu. Niektóre metodyki tworzenia oprogramowania zalecają jednak, aby… najpierw pisać kod testowy, a dopiero potem ten właściwy! Wbrew pozorom ma to całkiem spory sens. Jeśli bowiem zaczniemy od kodu, który ma naszej klasy używać, to istnieje większa szansa, że od początku wyposażymy ją w interfejs, którego rzeczywiście da się używać bez większych problemów. Na koniec zaś będziemy dysponowali też przykładowym kodem, obrazującym sposób korzystania z danej klasy, co zazwyczaj bywa przydatne.

Według mnie największą zaletą testów jednostkowych jest to, że przy pomocy odpowiednich narzędzi możemy je bardzo szybko napisać w postaci nadającej się do natychmiastowego uruchomienia. Brak konieczności tworzenia nowej aplikacji – dla samych tylko testów – jest niezwykle wygodny. Najczęściej bowiem jedyne, co musimy zrobić, to napisać klasę z procedurami testowymi i oznaczyć ją odpowiednio w kodzie, a następnie po prostu uruchomić testy (co często daje się zautomatyzować jako czynność następną po kompilacji) i obserwować wyniki.
Szczegóły mogą się aczkolwiek różnić w zależności od języka, jako że frameworków dla testów jednostkowych jest sporo. Mamy na przykład:

  • JUnit, przeznaczony dla Javy. To również pierwszy szeroko znany mechanizm tego typu i wzór dla licznych naśladowców (również pod względem nazewnictwa :-]).
  • NUnit to z kolei narzędzie dla .NET. Zasadniczo działa on bardzo podobnie do powyższego, również pod względem jego praktycznego użycia.
  • CppUnit to wreszcie próba przystosowania xUnit do języka C++. Wyszła ona całkiem zadowalająca, oczywiście zważywszy na to, co ów język oferuje chociażby w zakresie tak przydatnych tutaj refleksji (czyli mniej więcej tyle, co nic). Na pewno warto się tej bibliotece przyjrzeć.

Tak naprawdę to właściwie dla każdego liczącego się języka istnieje narzędzie tego typu. Polecam więc przyjrzenie się im (i całemu zagadnieniu testów jednostkowych), jeśli wcześniej nie mieliśmy z tym tematem styczności. Bo przecież testowania nigdy dość ;)

Tags: ,
Author: Xion, posted under Programming » 1 comment

Gorące testy

2007-07-18 18:38

W takich dniach jak dzisiejszy, gdy słupek rtęci w termometrze oscyluje w zdecydowanie zbyt wyżynnych okolicach, można żałować, że procesor w stojącym na biurku pececie pracuje dokładnie tak, jak mu fabryka nakazała i ani megaherca więcej. Dlaczego? Bo może wtedy nie obyło by się bez chłodzenia wodnego, co odjęłoby robiący w tych dniach krecią robotę radiator :)

W takich dniach kodowanie też jakoś za bardzo nie idzie, ale oczywiście jest to marnym usprawiedliwieniem nierobienia niczego pożytecznego. Skoro więc produkowanie nowego kodu nie przebiega tak płynnie jak zwykle, może warto zająć się kodem już istniejącym?… Ano warto – zwłaszcza jeśli pilnie wymaga on np. tak elementarnej czynności jak testowanie.
Przy tej okazji oczywiście nie raz i nie dwa pada najważniejsze pytanie, zadawane jak świat długi i szeroki przez wszystkich programistów, jacy kiedykolwiek chodzili po tej ziemi. Tak, chodzi naturalnie o gromkie:

Dlaczego to nie działa?!

To jest jednak tylko pytanie podstawowe, które można modyfikować w zależności od swojej programistycznej specjalności. I tak koderzy zajmujący się grafiką w ogóle, a programowanie w DirectX w szczególności mogą zmodyfikować je do równie dramatycznego:

Dlaczego nic nie widać?

Ten problem jest już na szczęście bardziej konkretny i stąd jego rozwiązanie powinno być łatwiejsze. Istotnie, na warsztatowym Wiki leży sobie nawet odpowiedni artykuł w formie listy kontrolnej, która wylicza sporo możliwości, mogących stać za problemami. Pocieszać można się jeszcze tym, że w 99% przypadków możemy przynajmniej zobaczyć coś innego niż nieprzeniknioną czerń – ja np. gustuję w czyszczeniu bufora tylnego na jaskrawozielony, opierając się wszechobecnej dyktaturze koloru niebieskiego ;P

Skoro tyle piszę o testowaniu, debugowaniu czy jak to ktoś “ładnie” spolszczył – odpluskiwaniu – to powinienem jeszcze wspomnieć, jakiż to kod poddaję tym mało wyszukanym operacjom. Jest to oczywiście pewien kawałek modułu grafiki 2D, który niedawno opisywałem.
Tak więc zgodnie ze starą prawdą, pisanie programu to rozkosz; uruchamianie programu to koszmar :) I chociaż może (oby!) nie zawsze jest tak w rzeczywistości, to jednak programiści są istotami wybitnie omylnymi i przez tę drugą, mniej przyjemną fazę tworzenia też trzeba przejść. I prawdę mówiąc, raczej nie ma co się nad nią dłużej rozwodzić :P

Tags: ,
Author: Xion, posted under Programming » Comments Off on Gorące testy
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.