miercuri, 20 mai 2009

Python mocking __new__

In acest tutorial voi prezenta o facilitate python extrem de interesanta: inlocuirea metodei speciale __new__. Acest lucru mi-a fost util in momentul in care am scris o suita de teste pentru o clasa. Problema era ca aceasta clasa era Singleton si in concluzie era dificil sa ma asigur ca resursele injectate sunt corecte de la un test la altul. Solutia de compromis a fost sa elimin comportamentul Singleton al clasei doar pentru teste.

class TestedClass(float):
def mockedNew(cls, *args, **kwds):
print("Mocked new")
self = float.__new__(*args, **kwds)
return self

def deleteNew(cls):
cls.__new__ = cls.mockedNew

def __new__(cls, arg=0.0):
"Convert from inch to meter"
print("Normal new")
return float.__new__(cls, arg*0.0254)

def __init__(self, arg=0.0):
print("Not working")

deleteNew = classmethod(deleteNew)
mockedNew = classmethod(mockedNew)

if __name__ == "__main__":
TestedClass.deleteNew()
print(TestedClass(12))

In mod normal, in exemplul de mai sus, daca nu as apela deleteNew rezultatul ar fi:
  • Normal new
  • Not working
  • 0.3048
Apeland deleteNew in main obtinem rezultatul:
  • Mocked new
  • Not working
  • 12
In aceasta maniera am reusit sa modific comportamentul metodei speciale __new__ in mod dinamic.

marți, 19 mai 2009

Python si Mocker

In acest tutorial voi prezenta un mod de testare care va ajuta sa eliminati dependentele(de scriere pe disk, de query-uri catre baze de date, etc...) si sa urmariti rularea propriu-zisa a algoritmului. Pentru a putea face acest lucru, trebuie sa permiteti functiei/clasei dumneavoastra sa "injecteze" obiecte in algoritm. In exemplul urmator vom arata cum se poate elimina dependenta de sistemul de fisiere.

def algoritm_complex(objOpen=open):
#aici vine rularea algoritmului

#aici vine partea de dependenta de hdd
f = objOpen("fisier.txt", "w")
f.write("testare simpla")
f.close()

Observam ca in functia de mai sus am furnizat un parametru cu valoare default buitin-ul open. In aceasta maniera in momentul in care functia va fi apelata intr-un mediu de productie nu va fi furnizat nici un parametru in timp ce in momentul in care se va dori testarea algoritmului se fa furniza o functie simulata. In continuare prezint partea de "mocking":

def test_AlgoritmComplex():
controller = Mocker()
objOpen = controller.mock()
fMocked = controller.mock()

objOpen.open("fisier.txt", "w")
controller.result(fMocked)

fMocked.write("testare simpla")

fMocked.close()

controller.replay()

algoritm_complex(objOpen.open)

Asta e tot ce aveti nevoie. Daca functia ar fi returnat un rezultat puteati face un assert pe valoarea returnata doar ca sa va asigurati ca algoritmul a functionat asa cum ati dorit. Pentru mai multe informatii despre acest mod de testare, vizitati site-ul http://labix.org/mocker.

joi, 7 mai 2009

Python si metod statice

Tinand cont ca am fost nevoit sa invat Python la noul loc de munca, am descoperit cateva elemente care se implementeaza un pic mai ciudat decat in Java. Unul din aceste exemple ar fi metodele statice.

In Java, o metoda statica se implementeaza in felul urmator:

public static void helloWorld() { System.out.println("Salutari"); }

In python lucrurile sunt mai complicate si depinde si de versiune folosita. De exemplu, daca folosim o versiune de python anterioara 2.4 atunci vom defini o metoda statica in felul urmator:

def helloWorld(cls):
print("Salutari")

helloWorld = classmethod(helloWorld)

Daca folosim o versiune mai noua de python lucrurile se simplifica deoarece putem folosi un decorator.
@staticmethod
def helloWorld(cls):
print("Salutari")

In ambele cazuri lucrurile sunt mai putin lizibile decat in Java. Oricum, asta este modul de a defini/folosi functii/metode statice in Python.