Solucionado (ver solução)
Solucionado
(ver solução)
5
respostas

Aplicar nova refatoração em testes após refatoração do código (Core)

Após aplicarmos a refaratoração no construtor da classe Leilao, para receber a modalidade, foram ajustados os métodos de testes para criar um novo leilão sempre utilizando a modalidade "básica" (new MaiorValor()). No momento que estamos desenvolvendo, seguindo o TDD, deveríamos ajustar nossos métodos de testes criados antes da refatoração do Leilao, para considerar todas as possíveis modalidades?

Por exemplo: O método NaoAceitaProximoLanceDadoMesmoClienteRealizouUltimoLance deveria ser trocado por [Theory] e receber todas as modalidades via [InlineData]?

5 respostas

Michel, bom dia.

Sim, essa é uma boa opção, usar [Theory] para testar modalidades diferentes. Mas tem duas observações:

Primeiro, o teste que vc mencionou possui a mesma expectativa mesmo que as modalidades sejam diferentes. Essa característica indica que o teste é um fato.

Agora considerando que desejamos fazer um teste para várias modalidades e verificar os lances ganhadores, indicando a necessidade de criar uma teoria (como vc acertadamente observou) precisaríamos usar outra forma de passar os valores de entrada do que [InlineData], uma vez que este é usado para valores simples ou arrays. Mencionei isso nessa atividade.

Para valores complexos precisaríamos usar uma das anotações [MemberData] ou [ClassData]. Vou escrever um teste usando essa idéia e postar aqui durante a semana, mas se topar o desafio poderia escrever também, que tal?

Olá Daniel, boa tarde. Obrigado pelo retorno. Entendi. Pensando em sua orientação cheguei no resultado abaixo:

Criei um novo método estático para retornar os dados complexos a serem testados. Um array de object que contém o valor esperado, um array de interessados (aproveitei para incluir os interessados dessa forma também), um array de ofertas e a instância de Leilao (variando a modalidade). Então:

public static IEnumerable<object[]> Dados()
        {
            var leilaoMaiorValor = new Leilao("Picasso", new MaiorValor());
            var leilaoOfertaProxima = new Leilao("Picasso", new OfertaSuperiorMaisProxima(1200));

            return new List<object[]>
            {
                new object[]
                {
                    1200,
                    new Interessada[] { new Interessada("Participante 1", leilaoMaiorValor ), new Interessada("Participante 2", leilaoMaiorValor) },
                    new double[] {800, 900, 1000, 1200}, leilaoMaiorValor },

                new object[] {
                    1210,
                    new Interessada[] { new Interessada("Participante 1", leilaoOfertaProxima ), new Interessada("Participante 2", leilaoOfertaProxima) },
                    new double[] {800, 1190, 1210, 1400}, leilaoOfertaProxima
                }
            };
        }

Com isso, criei um novo método de teste chamado: RetornaLanceGanhadorDadoLeilaoComDoisInteressadosDeVariasModalidadesEVariosLances utilizando os dados retornados através do método estático. Fiz um pequeno ajuste para considerar os interessados corretamente dentro do for de ofertas e não precisei mais instanciar Leilao. Ficando assim:

        [Theory]
        [MemberData(nameof(Dados))]
        public void RetornaLanceGanhadorDadoLeilaoComDoisInteressadosDeVariasModalidadesEVariosLances(
            double valorEsperado,
            Interessada[] interessadas,
            double[] ofertas,
            Leilao leilao)
        {
            //Arrange - cenário
            leilao.IniciaPregao();
            for (int i = 0; i < ofertas.Length; i++)
            {
                var valor = ofertas[i];
                if ((i % 2) == 0)
                {
                    leilao.RecebeLance(interessadas[0], valor);
                }
                else
                {
                    leilao.RecebeLance(interessadas[1], valor);
                }
            }

            //Act - método sob teste
            leilao.TerminaPregao();

            //Assert
            var valorObtido = leilao.Ganhador.Valor;
            Assert.Equal(valorEsperado, valorObtido);
        }

O que acha?

solução!

Boa, Michel, a idéia é essa mesmo. Parabéns!!

O que achou desse jeito de enviar dados de teste mais complexos do xUnit?

Legal! Achei bem completo. O xUnit dá uma flexibilidade muito grande na hora de criar os testes, até mesmo esses mais complexos. Pode ser através de Fact, parâmetros via InlineData, DataMember, podemos criar um método para retornar os dados complexos a serem testados como eu fiz ou organiza-lo em uma classe separada somente para isso. Muito legal.

Assim como seu curso, parabéns Daniel. Bem completo e ainda se preocupou com a organização do código e conceitos de boas práticas.

#GoAlura rsrs

Agradeço pelo feedback, Michel. Em breve um novo curso de testes com Selenium..