-
-
Save elissonmichael/211c2c4f480ea12d19aed68843ade173 to your computer and use it in GitHub Desktop.
| class Carrinho | |
| attr_reader :pedidos | |
| def initialize(args) | |
| @pedido_class = args[:pedido_class] | |
| @pedidos = [] | |
| end | |
| def adicionar(produto) | |
| @pedidos << @pedido_class.new(produto) | |
| end | |
| def produtos | |
| pedidos.map(&:produto) | |
| end | |
| def alterar_quantidade(produto, nova_quantidade) | |
| encontra_pedido_com(produto).alterar_quantidade(nova_quantidade) | |
| end | |
| def quantidade(produto) | |
| encontra_pedido_com(produto).quantidade | |
| end | |
| def total | |
| pedidos.sum(&:total) | |
| end | |
| private | |
| def encontra_pedido_com(produto) | |
| pedidos.detect{ |pedido| pedido.produto == produto } | |
| end | |
| end |
| require 'minitest/autorun' | |
| require_relative 'carrinho' | |
| describe Carrinho do | |
| def setup | |
| @carrinho = Carrinho.new(pedido_class: Minitest::Mock) | |
| @produto_dummy = Object.new | |
| @carrinho.adicionar(@produto_dummy) | |
| @pedido_mock = @carrinho.pedidos.first | |
| end | |
| describe :produtos do | |
| it "retorna os produtos adicionados" do | |
| @pedido_mock.expect(:produto, @produto_dummy) | |
| @carrinho.produtos.must_equal [@produto_dummy] | |
| end | |
| end | |
| describe :alterar_quantidade do | |
| it "envia uma mensagem de comando para pedido" do | |
| @pedido_mock.expect(:produto, @produto_dummy) | |
| @pedido_mock.expect(:alterar_quantidade, true, [3]) | |
| @carrinho.alterar_quantidade(@produto_dummy, 3) | |
| @pedido_mock.verify | |
| end | |
| end | |
| # Segundo Metz não precisamos testar mensagens de saída | |
| # que sejam apenas consultas, esse teste poderia ser removido. | |
| describe :total do | |
| it "envia uma mensagem de consulta para pedido" do | |
| @pedido_mock.expect(:total, 30) | |
| @carrinho.total | |
| @pedido_mock.verify | |
| end | |
| end | |
| end |
| class Pedido | |
| attr_reader :produto, :quantidade | |
| def initialize(produto) | |
| @produto = produto | |
| @quantidade = 1 | |
| end | |
| def alterar_quantidade(nova_quantidade) | |
| @quantidade = nova_quantidade | |
| end | |
| def total | |
| produto.preco * quantidade | |
| end | |
| end |
| require 'minitest/autorun' | |
| require_relative 'pedido' | |
| describe Pedido do | |
| def setup | |
| @produto_mock = MiniTest::Mock.new | |
| @pedido = Pedido.new(@produto_mock) | |
| end | |
| it "permite alterar a quantidade" do | |
| @pedido.alterar_quantidade(99) | |
| @pedido.quantidade.must_equal 99 | |
| end | |
| it "retorna o valor total" do | |
| @produto_mock.expect(:preco, 30) | |
| @pedido.total.must_equal 30 | |
| end | |
| end |
@elissonmichael eu injetaria uma classe para fazer a soma do preço dos itens no carrinho lá no construtor. Ai em vez de mockar pedido_class ali, você poderia injetar um somador dummy que sempre retorna um valor fixo.
class TotalizadorDummy
def total(lista_de_pedidos)
lista_de_pedidos.sum(&:total)
end
endA partir daí da pra brincar, por exemplo, com classes de desconto também, que poderiam ser injetadas no totalizador, tipo:
class DescontoBlackFriday
def aplica(lista_de_pedidos)
# 10% de desconto por item, até um máximo de 2 itens
lista_de_pedidos.size % 2 / 10
end
end
class TotalizadorDummy
def initialize(descontos = [])
@descontos = descontos
end
def total(lista_de_pedidos)
lista_de_pedidos.sum(&:total) * total_descontos
end
def total_descontos
@descontos.map { |desconto| desconto.aplica(lista_de_pedidos) }
end
endAtenção que minha brincadeira com descontos ai só funciona com porcentagem e é acumulativo (o total é multiplicado pela soma de todos descontos e cada desconto deve estar em forma decimal, por exemplo, 10% deve ser 0.10) e não multiplicativo.
Descontos poderiam ser decorators em cima do totalizador também, alterando como a função total funciona, não seria uma má idéia.
Obrigado @douglascamata, muito bom.
Uma alternativa é delegar a criação do pedido para uma fábrica, de modo que possa ser manipulada para retorrnar o objeto devido.
É também possível pensar as classes Carrinho e Pedido como um aggregate, e com essa visão talvez não seja necessário testá-las com um grau tão alto de isolamento.
Obrigado @rodrigomanhaes, gostei do aggregate.
@rodrigomanhaes eu queria implementar os testes de carrinho sem que ele dependesse de produto ou pedido (sua antiga classe item).
Eu não consegui fazer isso sem alterar a classe carrinho para poder injetar o Mock no construtor.