Testarea unei funcții care aruncă defecțiuni

Care este cel mai bun mod de a testa o funcție care aruncă asupra eșecului? Sau testarea unei funcții care este destul de imună la eșec?

De exemplu; Am o clasă I / O Completion Port care aruncă în constructor dacă nu poate inițializa corect portul. Aceasta utilizează funcția Win32 a CreateIoCompletionPort din lista inițializatorului. Dacă mânerul nu este setat corect - o valoare non-nulă - atunci constructorul va arunca o excepție. Nu am văzut niciodată că această funcție nu reușește.

Sunt destul de sigur că acest lucru (și alte funcții cum ar fi acesta în codul meu), dacă acestea nu reușesc să se comporte corect, codul are 50 de linii lungime, inclusiv spațiul alb, deci întrebările mele sunt

a) merită testat că va arunca b) și dacă merită testat, cum să?
c) ar trebui să fie simple clase de ambalare, deoarece acestea vor fi testate pe unitate?

Pentru b) m-am gândit la suprascrierea CreateIoCompletionPort și trecerea valorilor prin. În testul de unitate se suprascrie și se determină să se întoarcă 0 când o anumită valoare este trecută. Totuși, deoarece aceasta este utilizată în constructor, atunci aceasta trebuie să fie statică. Acest lucru pare valabil sau nu?

0
fr hi bn

4 răspunsuri

Este cu siguranță merită să testați condițiile de eșec, atât că clasa dvs. aruncă o excepție în mod corespunzător atunci când doriți și că excepțiile sunt tratate corespunzător în clasă.

Acest lucru se poate face cu ușurință dacă acționați pe un obiect care a trecut la constructor ... doar treceți într-o momeală. Dacă nu, am tendința de a prefera ca funcționalitatea să fie mutată într-o metodă protejată și să înlocuiască metoda protejată pentru a evoca cazul meu de eșec. Voi folosi Java ca exemplu, dar ar trebui să fie destul de ușor să port ideile într-un caz C #

public class MyClass {
    public MyClass() throws MyClassException {
        // Whatever, including a call to invokeCreateIoCompletionPort
    }

    protected int invokeCreateIoCompletionPort(String str, int i) {
        return StaticClass.createIoCompletionPort(str, i);
    }
}

public class MyTest {
    public void myTest() {
        try {
            new MyClass();
            fail("MyClassException was not thrown!");
        } catch (MyClassException e) {
        }
    }

    private static class MyClassWrapper extends MyClass {
        @Override
        protected int invokeCreateIoCompletionPort(String str, int i) {
            throw new ExpectedException();
        }
    }
}

După cum puteți vedea, este destul de ușor să testați dacă o excepție este aruncată de constructorul sau metoda pe care o testați și este, de asemenea, destul de ușor să injectați o excepție de la o clasă externă care poate arunca o excepție. Îmi pare rău că nu folosesc metoda dvs. reală, tocmai am folosit numele pentru a ilustra cum se pare că o folosiți și cum aș testa cazurile pe care ați vrut să le testați.

Practic, toate detaliile API pe care le expuneți pot fi de obicei testate și, dacă doriți să știți că cazurile excepționale funcționează așa cum ar trebui, probabil că veți dori să le testați.

0
adăugat

Dacă faceți acest lucru în .NET, există un atribut ExpectedException pe care îl puteți adăuga la testul dvs.:

[Test, ExpectedException(typeof(SpecificException), "Exception's specific message")]
public void TestWhichHasException()
{
    CallMethodThatThrowsSpecificException();
}

Testul va trece dacă excepția acelui tip și mesajul specificat sunt aruncate. Atributul are alte supraîncărcări incluzând Excepții interne, etc.

0
adăugat

Ar trebui să vă gândiți să scrieți codul în așa fel încât să puteți mânga portul de completare I / O. Faceți o interfață / clasă abstractă care expune metodele de care aveți nevoie pe obiectul I / O și scrieți și testați implementarea care face lucruri de genul lui (și probabil o opțiune de simulare a eșecului).

AFAIK este o practică obișnuită de a bate resursele externe atunci când testarea unității, pentru a minimiza dependențele.

0
adăugat

Sună ca C ++ pentru mine. Aveți nevoie de o cusătură pentru a elimina funcțiile Win32. De exemplu. în clasa dvs. ați crea o metodă protejată CreateIoCompletionPort() care solicită :: CreateIoCompletionPort() și pentru testul dvs. creați o clasă care derivă de la dvs. I / clasă și suprascrie CreateIoCompletionPort() pentru a nu face decât să returneze NULL . Clasa de producție se comportă încă ca și cum a fost proiectată, dar acum puteți simula un eșec în funcția CreateIoCompletionPort() .

Această tehnică este din cartea lui Michael Feathers "Lucrul eficient cu codul vechi".

0
adăugat