Jak napisac test jednostkowy dla takiej funkcji

Jak napisac test jednostkowy dla takiej funkcji
DC
  • Rejestracja:ponad 6 lat
  • Ostatnio:2 dni
  • Postów:325
0

Witam, mam problem napisanie unit testu dla funkcji loadTime,. Funkcja ta przerabia mape (timeTable) która: wygląda tak:
https://zapodaj.net/8ed88aaa570bb.png.html
na tablice result która składa sie z (0,1) - od indexu 3-5(03:00-05:00) to są jedynki i i od 12-14(12:00-14:00) to tez są jedynki dla reszty to są 0. I wtedy teblica result jest przypisywana do tablicy rowTable. Jak ja mogę napisać do tego unit test?

rowTable wyglada tak:

Kopiuj
  rowTable: Row[] = [
    { name: this.allDays.monday, items: new Array(24).fill(1), active: true },
    { name: this.allDays.tuesday, items: new Array(24).fill(1), active: true },
    { name: this.allDays.wednesday, items: new Array(24).fill(1), active: true },
    { name: this.allDays.thursday, items: new Array(24).fill(1), active: true },
    { name: this.allDays.friday, items: new Array(24).fill(1), active: true },
    { name: this.allDays.saturday, items: new Array(24).fill(1), active: true },
    { name: this.allDays.sunday, items: new Array(24).fill(1), active: true }
  ];

a funkcja docelowa: loadTime

Kopiuj
loadingTime(): void {
   if (this.inputObject?.timeTable) {
     let result = [...this.inputObject.timeTable].reduce((r, [key, value], i) => {
       r[i] = Array(24).fill(0);
       value.forEach(o => {
         let start = getHours(o.from);
         const end = getHours(o.to);
         while (start <= end) {
           r[i][start] = 1;
           start++;
         }
       })
       return r;
     }, []);
 
     this.rowTable.forEach((el, i) => {
       el.items = result[i];
       el.active = false;
     })
   }
 }

Kombinowalem jakos tak:

Kopiuj
it("should loading Time"), () => {
 
  const timetableMock = new Map<number, Array<HourScheduleDefinitionModel>>()
      timetableMock.set(0, [{ from: '00:00', to: '23:00' }]);
 
  component.loadingTime = () => {};
 
  const onSaveSpy = spyOn(component, "loadingTime")
 
  component.loadingTime();
 
  expect(onSaveSpy).toEqual([........]);
 
}

Ale mam wrażenie, ze robie to bez sensu. Prosze o pomoc

TS
  • Rejestracja:prawie 6 lat
  • Ostatnio:około 5 godzin
  • Postów:854
3

Przerób tę funkcję na coś takiego:

Kopiuj
y = f(x)

następnie Twoje testy powinny sprawdzić kilka przypadków w stylu:

Kopiuj
assert y1 == f(x1)
assert y2 == f(x2)

Jeżeli f(...) jest niedeterministyczne, tj. np. zależy od funkcji czasu to najlepiej spróbować wstrzyknąć tę funkcję czasu jako dodatkowy argument i ją zamockować tak, żeby jednak ta funkcja była deterministyczna, tj.

Kopiuj
assert y1 == f(x1, timerFun)

gdzie timerFun będzie np. zwracało zawsze tę samą datę.

edytowany 1x, ostatnio: twoj_stary_pijany
DC
a bez przerabiania tej funkcji da się ją przetestować? Czy raczej nie ma sensu tego robic?
TS
W dużym uproszczeniu można przyjąć, że jeżeli kod nie jest testowalny to jest źle napisany. Czasami testowalność wymusza refactoring i to jest jedna z zalet testowania kodu bo tworzymy dzięki temu lepszy kod.
DC
okej, czyli w skrocie ta funkcja nie jest testowalna
TS
Kod należy upraszczać. Ta funkcja przede wszystkim wygląda mi na bardzo skomplikowaną. Za 2 tygodnie sam nie będziesz kompletnie pamiętał co ona robi i jeżeli będzie tam jakiś błąd to spędzisz masę czasu na jego szukaniu. Czy jest testowalna? Wg mnie raczej nie, ale też nie jestem wyrocznią.
DC
  • Rejestracja:ponad 6 lat
  • Ostatnio:2 dni
  • Postów:325
0

Probowałem jednak cos tam pisać, ale mam błąd, że: TypeError: Cannot set properties of undefined (setting 'timeTable'). Wiesz o co chodzi?

Kopiuj
it('loadingTime should not update rowTable if timeTable is undefined', () => {
  const rowTableForEachSpy = jest.spyOn(component.rowTable, 'forEach');
  component.timeTable = void 0;
  component.loadingTime();
  expect(rowTableForEachSpy).not.toHaveBeenCalled();
})

it('loadingTime should update rowTable if timeTable is defined', () => {
  const rowTableForEachSpy = jest.spyOn(component.rowTable, 'forEach');
  component.timeTable =  new Map().set(0,[{from:"00:00", to:"23:00"];
  component.loadingTime();
  expect(rowTableForEachSpy).toHaveBeenCalled();
})
Xarviel
  • Rejestracja:ponad 3 lata
  • Ostatnio:dzień
  • Postów:847
1
dcielak napisał(a):

Probowałem jednak cos tam pisać, ale mam błąd, że: TypeError: Cannot set properties of undefined (setting 'timeTable'). Wiesz o co chodzi?

Kopiuj
it('loadingTime should not update rowTable if timeTable is undefined', () => {
  const rowTableForEachSpy = jest.spyOn(component.rowTable, 'forEach');
  component.timeTable = void 0;
  component.loadingTime();
  expect(rowTableForEachSpy).not.toHaveBeenCalled();
})

it('loadingTime should update rowTable if timeTable is defined', () => {
  const rowTableForEachSpy = jest.spyOn(component.rowTable, 'forEach');
  component.timeTable =  new Map().set(0,[{from:"00:00", to:"23:00"];
  component.loadingTime();
  expect(rowTableForEachSpy).toHaveBeenCalled();
})

Nie można ustawić wartości timeTable, pewnie z tym zapisem ma problem component.timeTable = void 0

Ogólnie co do kodu to próbujesz sprawdzić, czy metoda używa pętli forEach na tablicy
jest.spyOn(component.rowTable, 'forEach'); co według mnie jest kompletnie bez sensu. Jakikolwiek refaktor tej pętli na coś innego for of, for in, reduce itd będzie powodował także zmianę testów pomimo tego, że metoda tworzy ten sam rezultat.

Powinieneś to uprościć tak jak zasugerował @twoj_stary_pijany, albo sprawdzić, czy zmienił się stan komponentu po wywołaniu metody.

DC
tam gdzie zamockowalem timeTable, tez jest ten błąd, na razie nie chce przerabiac funkcji, może w przyszłości
Xarviel
Jeśli funkcja nic nie zwraca tylko modyfikuje stan komponentu to możesz sprawdzać, czy stan uległ zmianie, ale nie przez spyOn forEach. Metoda może w przyszłości zmieniać stan timeTable także poza pętla, a Twój test obecnie by tego nie wykrył.
DC
Taki test juz mam, chciałem jeszcze przetestować update rowTable gdy timeTable jest zdefiniowane, ale coś mi to nie działa i co mnie bardzo dziwi skoro timeTable jest zamockowane, a moze nie rozumiem czegos
Xarviel
A poprawiłeś ten zapis component.timeTable = void 0;, o którym wspomniałem?
.andy
  • Rejestracja:ponad 16 lat
  • Ostatnio:około 3 lata
  • Postów:1524
1

@dcielak:

Funkcja ta przerabia mape (timeTable) która: wygląda tak:
https://zapodaj.net/8ed88aaa570bb.png.html
na tablice result która składa sie z (0,1) - od indexu 3-5(03:00-05:00) to są jedynki i i od 12-14(12:00-14:00) to tez są jedynki

Test polega na tym, że sprawdzasz to co robi ta funkcja. Czyli np. wrzucasz ziemniaka do pudełka i na wyjściu otrzymujesz obranego ziemniaka i sprawdzasz czy ziemniak jest obrany?

Tak samo tutaj. Na wejściu wrzucasz mapę a na wyjściu otrzymujesz tablicę, która przyjmuje pewne wartości. Wystarczy że przygotujesz sobie mapę dla której masz wynik i porównasz ten wynik z tablicą która wypluje funkcja.


Software is like sex: it's better when it's free.
- Linus Torvalds

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.