No więc od początku:
test 'products is not valid without unique title' do
Zaczynamy test, który ma sprawdzić, że każdy produkt ma mieć swój unikalny tytuł. Wydaje mi się, że zamiast "products", powinno być "product". To tylko nazwa testu, ale "products" może być mylące.
product = Product.new(title: products(:ruby).title,
description: "aaaaaaa",
price: 1,
image_url: "fred.gif")
Na potrzeby testu tworzymy sobie nowy produkt według modelu z app/models/product.rb. Sprawdzamy unikalność title, więc jako title właśnie przyjmujemy tytuł który jest już w bazie danych. W testach używamy do tego pliku test/fixtures/products.yml, w którym dodajemy sobie produkty, który chcemy umieścić w testowej bazie danych. Używamy ich potem np. tak:
products(:ruby)
co odpowiada takiemu rekordowi w test/fixtures/products.yml :
ruby:
title: "Jakistytul"
description: "leelelel"
price: 13
image_url: "lol.gif"
Więcej o fixtures tutaj: http://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures
assert product.invalid?
Mamy dwa produkty o takim samym title. Jeden siedzi w bazie, drugi właśnie stworzyliśmy. Teraz chcemy zapewnić, że nasz lokalny product nie nadaje się do dodadania do bazy, więc product.invalid? powinno zwrócić true.
assert_equal ["has already been taken"], products.errors[:title]
Upewniliśmy się, że produkt nie nadaje się do bazy, teraz chcemy upewnić się, że powodem był zajęty title. Tutaj chyba wkradł się mały błąd, zamiast "products.errors[:title]" powinno być "product.error[:title]". "products" odnosi się do całej bazy danych, a nam chodzi o błąd naszego testowego produktu. assert_equal przechodzi test kiedy dwa podane argumenty są identyczne. product.errors[:title] zwraca nam tablicę z wiadomościami o błędach dotyczących :title, dlatego porównujemy to z ["has already been taken"] - taką właśnie wiadomość błędu powinniśmy otrzymać. Więcej tutaj: http://guides.rubyonrails.org/active_record_validations.html#validations-overview-errors
BTW. Jeśli w product.errors[:title] znajdowałyby się jakieś inne błędy, test by nie przeszedł. Żeby tego uniknąć możnaby zamiast assert_equal napisać np:
assert product.errors[:title].include?("has already been taken")
Oczywiście, że cały ten test przeszedł w modelu produktu musi znaleźć się taki kod:
class Product < ApplicationRecord
.
.
.
validates :title, uniqueness: true
.
.
.
end