É um teste unitário considerado frágil se falhar quando a lógica de negócios muda?

27

Por favor, veja o código abaixo; testa para ver se uma pessoa com sexo feminino é elegível para oferta1:

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id,"Offer1");
    Assert.False(offer1.IsEligible(person));
}

Este teste unitário é bem-sucedido. No entanto, ele falhará se "Oferta1" for oferecida às mulheres no futuro.

É aceitável dizer que, se a lógica de negócios que envolve a oferta 1 mudar, o teste de unidade deve ser alterado. Observe que, em alguns casos (para algumas ofertas), a lógica de negócios é alterada no banco de dados da seguinte forma:

update Offers set Gender='M' where offer=1;

e, em alguns casos, no modelo de domínio como este:

if (Gender=Gender.Male)
{
  //do something
}

Observe também que, em alguns casos, a lógica de domínio por trás oferece alterações regularmente e, em alguns casos, não.

    
por w0051977 24.12.2018 / 13:02
fonte

2 respostas

77

Isso não é frágil no sentido usual. Um teste unitário é considerado frágil se quebrar devido a alterações de implementação que não afetam o comportamento sob teste. Mas se a própria lógica de negócios mudar, então um teste dessa lógica é supostamente para quebrar.

Se a lógica de negócios realmente mudar com frequência, talvez não seja apropriado codificar as expectativas nos testes de unidade. Em vez disso, você poderia testar se as configurações no banco de dados afetam as ofertas conforme o esperado.

O nome do teste Returns False When Given A Person With A Gender Of Female não descreve uma regra de negócios. Uma regra de negócios seria algo como Offers Applicable to M should not be applied to persons of gender F .

Para que você possa escrever um teste que confirme que se uma oferta é definida como aplicável apenas a pessoas do tipo M, uma pessoa do tipo F não será indicada como elegível para ela. Esse teste garantirá que a lógica funcione mesmo se a configuração das ofertas específicas for alterada.

    
por 24.12.2018 / 13:28
fonte
14

Quando a propriedade é definida no banco de dados de produção (ou um clone para teste), isso não é um teste de unidade . Um teste de unidade verifica uma unidade de trabalho e não requer um estado externo específico para funcionar. Isso pressupõe que Offer1 seja definido no banco de dados para ser uma oferta somente para homens. Isso é estado externo. Então, isso é mais um teste de integração , especificamente um system ou acceptance . Observe que os testes de aceitação geralmente não são roteirizados (não executados em uma estrutura de teste, mas executados manualmente por seres humanos).

Quando a propriedade é definida no modelo de domínio com uma instrução if , o mesmo teste é um teste de unidade. E isso pode ser frágil. Mas o verdadeiro problema é que o código é frágil. Como regra geral, seu código será mais resiliente se o comportamento de negócios for configurável em vez de codificado. Porque uma implantação urgente para corrigir um pequeno erro de codificação deve ser rara. Mas um requisito comercial que muda sem aviso prévio é apenas uma terça-feira (algo que acontece semanalmente).

Você pode estar usando uma estrutura de teste de unidade para executar o teste. Mas as estruturas de teste de unidade não se limitam a executar testes de unidade. Eles podem e executam testes de integração também.

Se você estivesse escrevendo um teste de unidade, criaria person e offer1 do zero sem depender do estado do banco de dados. Algo como

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
    offer1.markLimitedToGender("M");

    Assert.False(offer1.IsEligible(person));
}

Observe que isso não muda com base na lógica de negócios. Não está afirmando que offer1 rejeita as mulheres. Está fazendo offer1 o tipo de oferta que rejeita as mulheres.

Você pode criar e configurar o banco de dados como parte do teste. Em C #, usando o NUnit, ou no Java JUnit, você configuraria o banco de dados em um método Setup . Presumivelmente, sua estrutura de teste tem uma noção semelhante. Nesse método, você poderia inserir registros no banco de dados com o SQL.

Se for difícil para você escrever um código que substitua um banco de dados de teste para o banco de dados de produção, isso parece uma fraqueza de teste em seu aplicativo. Para testes, seria melhor usar algo como injeção de dependência que permita a substituição. Então você poderia escrever testes que são independentes das regras de negócios atuais.

Um benefício colateral disso é que muitas vezes é mais fácil para o proprietário da empresa (não necessariamente o proprietário da empresa, mais como a pessoa responsável por esse produto na hierarquia corporativa) configurar as regras de negócios diretamente. Porque, se você tiver esse tipo de estrutura técnica, será fácil permitir que o proprietário da empresa use uma interface do usuário (UI) para configurar a oferta. O proprietário da empresa selecionaria a limitação na interface do usuário e emitiria a chamada markLimitedToGender("M") . Então, quando a oferta for mantida no banco de dados, ela será armazenada. Mas você não precisaria armazenar a oferta para usá-lo. Portanto, seus testes podem criar e configurar uma oferta que não existe no banco de dados.

Em seu sistema, conforme descrito, o proprietário da empresa teria que fazer uma solicitação ao grupo técnico, que emitiria o SQL apropriado e atualizaria os testes. Ou o grupo técnico tem que editar seu código e testes (ou testes então codificam). Isso parece uma abordagem bastante pesada. Você consegue. Mas o seu software (não apenas o seu teste) seria menos frágil se você não tivesse que fazê-lo.

TL; DR : você pode escrever testes como esse, mas talvez seja melhor escrever seu software para não precisar fazê-lo.

    
por 24.12.2018 / 18:00
fonte