Chciałem nauczyć się korzystać z podejścia TDD i miałem projekt, nad którym chciałem pracować od dłuższego czasu. To nie był duży projekt, więc pomyślałem, że będzie dobrym kandydatem do TDD. Czuję jednak, że coś poszło nie tak. Podam przykład:
Na wysokim poziomie mój projekt jest dodatkiem do Microsoft OneNote, który pozwoli mi łatwiej śledzić i zarządzać projektami. Teraz chciałem zachować logikę biznesową w tym zakresie możliwie jak najbardziej oddzieloną od OneNote, na wypadek, gdyby któregoś dnia postanowiłem zbudować własną pamięć masową i zaplecze.
Najpierw zacząłem od podstawowego testu akceptacji prostych słów, który nakreślił, co chciałbym, aby moja pierwsza funkcja była zrobiona. Wygląda to mniej więcej tak:
- Kliknięcia użytkownika tworzą projekt
- Typy użytkowników w tytule projektu
- Sprawdź, czy projekt został poprawnie utworzony
Pomijam interfejs użytkownika i trochę planowania pośredniego, przechodzę do pierwszego testu jednostkowego:
[TestMethod]
public void CreateProject_BasicParameters_ProjectIsValid()
{
var testController = new Controller();
Project newProject = testController(A.Dummy<String>());
Assert.IsNotNull(newProject);
}
Jak na razie dobrze. Czerwony, zielony, refaktor itp. W porządku, teraz potrzebuje rzeczy. Wycinając tutaj kilka kroków, kończę z tym.
[TestMethod]
public void CreateProject_BasicParameters_ProjectMatchesExpected()
{
var fakeDataStore = A.Fake<IDataStore>();
var testController = new Controller(fakeDataStore);
String expectedTitle = fixture.Create<String>("Title");
Project newProject = testController(expectedTitle);
Assert.AreEqual(expectedTitle, newProject.Title);
}
W tym momencie nadal czuję się dobrze. Nie mam jeszcze konkretnego magazynu danych, ale stworzyłem interfejs tak, jak się spodziewałem.
Pominę tutaj kilka kroków, ponieważ ten post jest wystarczająco długi, ale postępowałem zgodnie z podobnymi procesami i ostatecznie przechodzę do tego testu dla mojego magazynu danych:
[TestMethod]
public void SaveNewProject_BasicParameters_RequestsNewPage()
{
/* snip init code */
testDataStore.SaveNewProject(A.Dummy<IProject>());
A.CallTo(() => oneNoteInterop.SavePage()).MustHaveHappened();
}
To było dobre, dopóki nie spróbowałem go zaimplementować:
public String SaveNewProject(IProject project)
{
Page projectPage = oneNoteInterop.CreatePage(...);
}
I jest problem właśnie tam, gdzie jest „...”. W tym momencie zdaję sobie sprawę, że CreatePage wymaga identyfikatora sekcji. Nie zdawałem sobie z tego sprawy, kiedy myślałem na poziomie kontrolera, ponieważ byłem zainteresowany jedynie testowaniem bitów istotnych dla kontrolera. Jednak przez całą drogę zdaję sobie sprawę, że muszę poprosić użytkownika o miejsce do przechowywania projektu. Teraz muszę dodać identyfikator lokalizacji do magazynu danych, następnie dodać jeden do projektu, następnie dodać jeden do kontrolera i dodać go do WSZYSTKICH testów, które są już napisane dla wszystkich tych rzeczy. Szybko stało się to żmudne i nie mogę się powstrzymać, ale czuję, że złapałbym to szybciej, gdyby naszkicowałem projekt z wyprzedzeniem, zamiast pozwolić mu zaprojektować go podczas procesu TDD.
Czy ktoś może mi wyjaśnić, czy w tym procesie zrobiłem coś złego? Czy można zrezygnować z tego rodzaju refaktoryzacji? Czy to jest powszechne? Jeśli jest to powszechne, czy są jakieś sposoby na uczynienie go bardziej bezbolesnym?
Dziękuje wszystkim!