Download - Dubles de teste
Dublês de Teste@marcosbrizeno
Mocks ou Dublês
Mock -> Um tipo de Dublê
Dublê -> Stub,Fake,Dummy,Spy e Mock
Formalmente -> Dublê de Teste (Test Double)
Informalmente -> Mock
Stubs
Substitui um comportamento
Pode retornar um valor
def find_overpriced_items_in(items_list) items = Item.find(items_list) items.select do |item| average_price = AveragePrice::Service.get_average_price(item.global_id) item.price > (average_price * 1.2) endend
should "return all overpriced items in the list" do overpriced_item = Factory.create_item :price => 125 AveragePrice::Service.stubs(:get_average_price).returns(100) assert_equal [overpriced_item], find_overpriced_items_in([overpriced_item])end
ExemploWeb
service
Stub do web service
Fake
Substitui um objeto
module AveragePrice class Service def get_average_price(global_id) 100 end endend
Exemplo
should "return all overpriced items in the list" do overpriced_item = Factory.create_item :price => 125 assert_equal [overpriced_item], find_overpriced_items_in([overpriced_item])end
Fake
Podem ter regras
module AveragePrice class Service ITEM_PRICE_100 = 1 ITEM_PRICE_200 = 2 def get_average_price(global_id) return 100 if(global_id == ITEM_PRICE_100) return 200 if(global_id == ITEM_PRICE_200) 150 end endend
Exemplo
Stub vs Fake
Dummy
Substitui um objeto
Não possui lógica
class DummyItem def method_missing(method, *args, &block) nil endend
Exemplo
Dummy
Exemplo
should "return false if item price is less or equal than 20% plus average price" do dummy_item = DummyItem.new promo_item = PromoItem.new(dummy_item, :price => 100) AveragePrice::Service.stubs(:get_average_price).returns(120) assert_false promo_item.overpriced?end
should "return false if item price is less or equal than 20% plus average price" do promo_item = PromoItem.new(nil, :price => 100) AveragePrice::Service.stubs(:get_average_price).returns(120) assert_false promo_item.overpriced?end
tanto faz
Dummy
Fake vs Dummy
Dummy é um Fake simplificado
Fake vs DummyVoce pode não saber que usa
Mock
Testar chamada de métodos
Parâmetros
Número de vezes
class PromoItem def initialize(item) @item = item end! def overpriced? price > (AveragePrice::Service.get_average_price(@item.global_id)*1.2) endend
should "use AveragePrice service to get the average price" do item = Factory.create_item(:global_id => 99) promo_item = PromoItem.new(item, :price => 100)! AveragePrice::Service.expects(:get_average_price).with(item.global_id).once promo_item.overpriced?end
Exemplo
chamada esperada
uma única vez
parâmetro específico
Spy
Testar chamada de métodos
Parâmetros
Número de vezes
def remove_overpriced_items_in(items) items.reject do |item| item.overpriced? endend
should "use AveragePrice service to get the average price" do item_spy = mock() remove_overpriced_items_in([item_spy]) assert_received(item_spy, :overpriced) do |expect| expect.once endend
Exemplo
chamada esperadauma única
vez
Mock vs Spy
Configuração
Ação
Asserção
Configuração
Expectativa
Ação
Mock vs SpyAlto acoplamento
Só Dublê
Rápidos
IsoladosSem significado
Só Dublêshould “break hope in humanity" do item = Item.new item.stubs(:price).returns(200) assert_equal 200, item.priceend
Sem Dublê
Dependências explícitas
Teste real
Impossível
Sem Dublêdef promo_items_not_sold PromoItems.all( :conditions => ["created_on <= ? AND sold != ?”, DateTime.now - 2.days, true])end
Moar links
http://blog.8thlight.com/uncle-bob/2014/05/14/TheLittleMocker.html
https://www.destroyallsoftware.com/blog/2014/test-isolation-is-about-avoiding-mocks
http://www.thoughtworks.com/insights/blog/mockists-are-dead-long-live-classicists
www.thoughtworks.com/insights/blog/write-better-tests-5-steps
Obrigado