Jak testować wyłącznie metodę zmieniającą stan obiektu?

Uczę się programować TDD. Nie istotne w jakim frameworku, bo próbuję różnych, tak jak nie ważne jaką klasę, bo ten problem ciągle napotykam w różnych swoich wymyślanych “kata”.

Powiedzmy, że jest sobie klasa która ma takie metody:
load(something),
update,
check_state.
Zasada działania polega na tym, że load z podanym argumentem inicjuje stan obiektu, update modyfikuje ten stan i ma do niego dostęp, żeby się po danych iterować itd., a check_state to wiadomo, tylko zwraca stan.

Przetestowałem już metodę load, w ten sposób, że wywoływałem ją z jakimiś argumentami i sprawdzałem czy check_state będzie dawało poprawny wynik. Teraz chodzi mi o testowanie update. Zrobiłem to tak, że właściwie najpierw tak samo jak w poprzednich testach załadowałem dane do obiektu, żeby mieć jakiś stan, a potem wywoływałem update i znowu sprawdzałem czy stan obiektu jest taki jak być powinien.

I tutaj mam wątpliwości, bo ten test chyba testuje dwie rzeczy: load i update, a nie tylko jedną. Pomyślałem, że może lepiej jakbym zamiast tego load jakoś mógł stworzyć od razu taki stan jaki chcę i na nim zrobić update. Tylko ja w tej klasie nie potrzebuję żadnej metody set_state, no chyba że tylko do testów. Pytanie brzmi, co zrobić, żeby testować tylko update?

ten load to brzmi jak initialize albo to nim powinien byc, update ok, check_state to juz inna klasa dla mnie

ale pokolej:

class UpdateKlass # or Klass::Update ... co tam lubi kto
  attr_reader :id, :params

  def initialize(id, params)
    @id = id
    @params = params
  end

  def call
    ... # sth to persist object
  end
end

class FetchKlass
  attr_reader :id

  def initialize(id)
    @id = id
  end

  def call
    ... # sth to fetch single record
  end
end

Dzieki temu masz 2 servisy ktore robia jedna rzecz, Mozesz je latwo przetestowac, jesli nie wiesz jak przetestowac je to daj znac to napisze pelen przyklad

ps nie wiem czy dobrze zrozumiałem ale moze twoje pytanie dotyczy bardziej mock/stub jesli tak to wtedy: https://github.com/rspec/rspec-mocks

Tak, load to w zasadzie mogłoby być initialize. Mówisz, że mam z każdej metody klasy zrobić osobną klasę? Myślałem, że moja klasa jest wystarczająco mała, chociaż planowałem pododawać jeszcze inne pola i attr_reader do nich,ale zmiana ich byłaby w update.

O stubowaniu myślałem, ale mi nie wychodzi. Zastubowałem metodę check_state, w zasadzie to powinna się tu nazywać po prostu state.
Powiedzmy, że jest tak:

class Foo
  attr_reader :state
  
  def load(raw_data)
    nice_data = []
    # some complex stuff
    @state = nice_data
  end

  def update
    items_to_delete = []
    self.state.each do |item|
      # something
    end
    @state -= items_to_delete
  end

end

Teraz powiedzmy, że to zastubuję:
foo = Foo.new
allow(foo).to receive(:state) { [1,2,3,4,5,6,7,8] }

i nie działa update, bo w tym obiekcie @state jest nilem.

no ja bym dal service (klase) ktora robi jedna rzecz, np Update, czy Fetch

i na pewno zmienil load na initializer, i wtedy masz cos jak

 let(:foo) { Foo.new(params) } # params to twoj stan obiektu, i wtedy instacja bedzie miala stan juz

 it do
   expect(foo.update).to eql({...})
 end

Nic tutaj stubowac nie musisz i nie testujesz dwoch rzeczy, tylko inicjalizujesz stan do testu. Lepiej unikac stubow, mockow jak nie sa potrzebne

Patrząc na to, przyszło mi na myśl, że właściwie to new może przyjmować gotowe, ładne dane, a load dane do obróbki. Wtedy chyba już nie można mówić, że przygotowanie obiektu do testu za pomocą new to dodanie dodatkowej rzeczy, która może w teście pójść źle? Bo całe moje wątpliwości biorą się z tego, że mogę mieć bug w tym load, a wezmę to za bug w update. No i niewygodne jest samemu ciągle pilnować, żeby podać takie dane, żeby po wstępnych przeróbkach do update trafiło to co chcę (może być bug w założeniach samego testu).

W takim wypadku nie widzę już potrzeby robienia klas Update i Fetch. I czy miałyby one być statyczne?

No jest dyskusja a raczej duzo dluzsza nauka niz mozliwosci postu i forum. Uczysz sie sam? Masz jakies dobre zrodlo wiedzy? Ciezko mi tu bedzie ci wytlumaczyc czemu tak jak napisalem wyzej to “powinno” wygladac i jak to testowac i ogolnie jak powinna cala apikacja wygladac, jak organizowac kod … Jest w internecie mnostwo materiałów + masa czasu i tyle znajdziesz wszystko i zrozumiesz. ale duzo latwiej pojsc do jakiejs dobrej firmy na staz/praktyki, tam naucza sie wszystekigo kilka razy szybciej.

Powodzenia

Powodzenia z tym poszukiwaniem!

Firmy chcą zatrudniać Mida za pensję Juniora z wiedzą Seniora!

Nie a co demonizować. Jest na pewno trudniej zacząć pracę w tym zawodzie niż kiedyś, ale też technologie których się używa w pracy są coraz bardziej skomplikowane i rozbudowane. Stąd rosnące wymagania.

Jeśli chodzi o praktyki, to z bardzo podstawową wiedzą z jakiegokolwiek programowania można się na nie dostać (wiem co mówię, bo sam niejednokrotnie praktyki prowadziłem i decydowałem o tym kto się na nie dostanie). Po nich ma się praktycznie gwarancje zatrudnienia w którejś firmie na rynku.

By dostać pracę jako junior trzeba:

  • biegły angielski (to w sumie bywa ważniejsze niż wszystko inne)
  • podstawy ruby oraz rails
  • cos tam z html/css
  • jakieś podstawy z js

I tyle

Uczę się na własną rękę z tego co znajdę w necie i tego co powiedzą mi inni na forum czy przez komunikator. Ale jeśli chodzi o testy, to znajduję jedynie urywki wiedzy (inna rzecz, że nie zainwestowłem jeszcze w żadną książkę ani kurs o testowaniu, a zainwestowałem w te rzeczy jeśli chodzi o Ruby i Rails), a chciałbym opanować testowanie, wyrobić sobie nawyk robienia tego i użyć do swoich “prac dyplomowych”, które potem mógłbym pokazać komuś.

jest dużo materiałów za free, do testowania też. Było masa wątków tutaj na forum.

Ale nigdzie tak sie nie nauczysz jak w firmie od innych devow. Napisz na github poprawny kod w rails, otestuj jak potrafisz i uderzaj do pracy. Szkoda czasu na czekanie, samemu nie osiagniesz poziomu pewnego. Praktycznie sie nie da.

Tak, ale niektóre pytania zostają całkowicie bez odpowiedzi, jakby nikt z użytkowników tego forum nie używał RSpec. :open_mouth:

RSpec ... co warto sprawdzać? (dublowanie testów)

Szkoda, bo wielu z nas, tak jak kolega @Str, czy ja, uczy się samodzielnie i naprawdę patrzy na to forum jak na wyrocznię, Olimp jakiś, gdzie Bogowie Railsów są ostatnią instancją rozstrzygającą nasze wątpliwości.

Niestety wiele osob ktore kiedys tworzyly to forum teraz ma wlasnefirsy, duze projekty na glowie i deficyt czasu, ale na pewno jak pytanie jest dobrze sformuowane to w koncu ktos odpowie. Sam tak zaczynalem nauke i dzieki pomocy ludzi z tego forum napisalem kilka pierwszych apek, ale dopiero programowac w ruby nauczylem sie pracujac z innymi devami w projekcie. Samemu niestety uczysz sie bardzo nie rowno i “niepokolei”, jesli tylko mozesz to idz nawet za darmo na staz do jakiejkolwiek firmy lokalnie (kontakt face-2-face) jak sie jest juniorem daje duzo