Szukaj…


Wprowadzenie

Test jednostkowy jest najmniejszą testowalną częścią aplikacji, taką jak funkcje, klasy, procedury, interfejsy. Testowanie jednostkowe to metoda, według której poszczególne jednostki kodu źródłowego są testowane w celu ustalenia, czy nadają się do użycia. Testy jednostkowe są w zasadzie pisane i wykonywane przez twórców oprogramowania, aby upewnić się, że kod spełnia jego wymagania projektowe i zachowuje się zgodnie z oczekiwaniami.

Dobre nazewnictwo

Znaczenie dobrego nazewnictwa najlepiej ilustrują złe przykłady:

[Test]
Test1() {...} //Cryptic name - absolutely no information 

[Test]
TestFoo() {...} //Name of the function - and where can I find the expected behaviour?

[Test]
TestTFSid567843() {...} //Huh? You want me to lookup the context in the database?

Dobre testy wymagają dobrych nazwisk. Dobry test nie testuje metod, scenariuszy testowych ani wymagań.

Dobre nazewnictwo zapewnia również informacje o kontekście i oczekiwanym zachowaniu. Idealnie, gdy test zakończy się niepowodzeniem na komputerze kompilacyjnym, powinieneś być w stanie zdecydować, co jest nie tak, bez patrzenia na kod testowy, a nawet trudniej, z koniecznością debugowania go.

Dobre nazewnictwo oszczędza czas na czytanie kodu i debugowanie:

[Test]
public void GetOption_WithUnkownOption_ReturnsEmptyString() {...}
[Test]
public void GetOption_WithUnknownEmptyOption_ReturnsEmptyString() {...}

Dla początkujących pomocne może być uruchomienie nazwy testu z gwarantowanym prefiksem. Zacznij od „Zadbaj o to”, aby zacząć myśleć o scenariuszu lub wymaganiu, które wymaga testu:

[Test]
public void EnsureThat_GetOption_WithUnkownOption_ReturnsEmptyString() {...}
[Test]
public void EnsureThat_GetOption_WithUnknownEmptyOption_ReturnsEmptyString() {...}

Nazewnictwo jest ważne także dla urządzeń testowych. Nazwij urządzenie testowe po testowanej klasie:

[TestFixture]
public class OptionsTests //tests for class Options
{
    ...
}

Ostateczny wniosek jest następujący:

Dobre nazewnictwo prowadzi do dobrych testów, które prowadzą do dobrego zaprojektowania kodu produkcyjnego.

Od prostych do złożonych

Tak samo, jak w przypadku pisania klas - zacznij od prostych przypadków, a następnie dodawaj wymagania (aka testy) i implementację (aka kod produkcyjny) dla każdego przypadku:

[Test]
public void EnsureThat_IsLeapYearIfDecimalMultipleOf4() {...}
[Test]
public void EnsureThat_IsNOTLeapYearIfDecimalMultipleOf100 {...}
[Test]
public void EnsureThat_IsLeapYearIfDecimalMultipleOf400 {...}

Nie zapomnij o kroku refaktoryzacji, gdy zakończysz z wymaganiami - najpierw refaktoryzuj kod, a następnie refaktoryzuj testy

Po zakończeniu powinieneś mieć pełną, aktualną i DOKŁADNĄ dokumentację swojej klasy.

Koncepcja MakeSut

Kod testowy ma takie same wymagania jakościowe, jak kod produkcyjny. MakeSut ()

  • poprawia czytelność
  • można łatwo refaktoryzować
  • doskonale obsługuje wstrzykiwanie zależności.

Oto koncepcja:

[Test]
public void TestSomething()
{
    var sut = MakeSut();
    
    string result = sut.Do();
    Assert.AreEqual("expected result", result);
}

Najprostsza funkcja MakeSut () zwraca właśnie testowaną klasę:

private ClassUnderTest MakeSUT()
{
    return new ClassUnderTest();
}

Gdy potrzebne są zależności, można je wprowadzić tutaj:

private ScriptHandler MakeSut(ICompiler compiler = null, ILogger logger = null, string scriptName="", string[] args = null)
{
    //default dependencies can be created here
    logger = logger ?? MockRepository.GenerateStub<ILogger>();
    ...
}

Można powiedzieć, że MakeSut jest po prostu prostą alternatywą dla metod konfiguracji i porzucania dostarczanych przez frameworki Testrunner i może uważać te metody za lepsze miejsce do konfiguracji i porzucania testów.

Każdy może sam zdecydować, którego użyć. Dla mnie MakeSut () zapewnia lepszą czytelność i znacznie większą elastyczność. Wreszcie, koncepcja jest niezależna od jakiegokolwiek frameworka testrunner.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow