Pergunta

Suponha que você tenha um método:

public void Save(Entity data)
{
    this.repositoryIocInstance.EntitySave(data);
}

Você escrever um teste de unidade em tudo?

public void TestSave()
{
    // arrange
    Mock<EntityRepository> repo = new Mock<EntityRepository>();
    repo.Setup(m => m.EntitySave(It.IsAny<Entity>());

    // act
    MyClass c = new MyClass(repo.Object);
    c.Save(new Entity());

    // assert
    repo.Verify(m => EntitySave(It.IsAny<Entity>()), Times.Once());
}

Porque mais tarde, se você fizer a implementação do método de mudança para fazer mais coisas "complexo" como:

public void Save(Entity data)
{
    if (this.repositoryIocInstance.Exists(data))
    {
        this.repositoryIocInstance.Update(data);
    }
    else
    {
        this.repositoryIocInstance.Create(data);
    }
}

... o teste de unidade seria um fracasso, mas ele provavelmente não iria quebrar a sua aplicação ...

Pergunta

Eu deveria mesmo se preocupar criação de testes unitários em métodos que não tem nenhum tipos de retorno * ou ** Não mude nada fora de simulação interna ?

Foi útil?

Solução

É verdade o teste está dependendo de sua implementação, o que é algo que você deve evitar (embora não é realmente assim tão simples às vezes ...) e não é necessariamente ruim. Mas este tipo de testes são esperados para quebrar mesmo se a sua mudança não quebrar o código .

Você pode ter muitas abordagens para isso:

  • Criar um teste que realmente vai para o banco de dados e verifique se o estado foi alterado conforme o esperado (ele não ser um unidade test anymore)
  • Criar um objeto de teste que simula um banco de dados e fazer operações in-memory (outra aplicação para o seu repositoryIocInstance), e verificar o estado foi alterado conforme o esperado. Alterações ao interface de repositório iria incorrer em alterações a este objeto também. Mas suas interfaces não deve mudar muito, certo?
  • Veja tudo isso como muito caro, e usar a sua abordagem, que pode incorrer em testes desnecessariamente quebrando mais tarde (mas uma vez que a chance é baixa, é ok para assumir o risco)

Outras dicas

Não se esqueça que os testes de unidade não é apenas sobre o teste de código. É sobre o que lhe permite determinar quando as mudanças de comportamento .

Assim você pode ter algo que é trivial. No entanto, a sua implementação muda e você pode ter um efeito colateral. Você quer que seu conjunto de testes de regressão para lhe dizer.

por exemplo. Muitas vezes as pessoas dizem que você não deve testar setters / getters já que eles são trivial. Eu discordo, não porque eles são métodos complicados, mas alguém pode inadvertidamente mudá-los por ignorância, cenários de gordura dos dedos etc.

Dado tudo o que acabei de dizer, eu definitivamente implementar testes para o acima (via zombando, e / ou, talvez vale a pena projetar suas aulas com capacidade de teste em mente e tê-los relatar o status etc.)

Pergunte a si mesmo duas perguntas. "Qual é o equivalente manual deste teste de unidade?" e "vale a pena automatizar?". No seu caso, seria algo como:

O que é equivalente manual? - depurador início - passo no método "Save" - passo para a próxima, certifique-se você está dentro de implementação IRepository.EntitySave

Vale a pena automatizar? Minha resposta é "não". É 100% óbvio a partir do código. De centenas de testes de resíduos semelhantes eu não vi um único que viria a ser útil.

A regra geral é que você teste todas as coisas, que provavelmente poderia quebrar. Se você tem certeza, que o método é bastante simples (e estadias bastante simples) para não ser um problema, que deixá-lo fora com o teste.

A segunda coisa é, você deve testar o contrato do método, não a implementação. Se o teste falhar após uma mudança, mas não a aplicação, em seguida, o teste não testa a coisa certa. O teste deve abranger os casos que são importantes para a sua aplicação. Isso deve garantir que todas as alterações ao método que não quebrar o aplicativo também não falhar no teste.

A curta resposta à sua pergunta é:. Sim , você deve definitivamente métodos de ensaio como esse

Eu suponho que é importante que o método Save realmente salva os dados. Se você não escrever um teste de unidade para isso, então como você sabe?

Alguém pode vir e remover essa linha de código que chama o método EntitySave, e nenhum dos testes de unidade irá falhar. Mais tarde, você está se perguntando por itens nunca são persistentes ...

Em seu método, você poderia dizer que ninguém apagar essa linha só seria fazê-lo se eles têm intenções malignas, mas a coisa é: As coisas simples não necessariamente permanecer simples, e é melhor você escrever os testes de unidade antes de as coisas complicado.

É não um detalhe de implementação que o método Save invoca EntitySave no Repositório - é parte do comportamento esperado, e uma parte muito importante, se assim posso dizer. Você quer ter certeza de que os dados realmente está sendo salvo.

Só porque um método não retorna um valor não significa que não vale a pena testar. Em geral, se você observar bem Command / consulta separação (CQS), qualquer método vazio deve ser esperado para alterar o estado de algo .

Às vezes, esse algo é a própria classe, mas outras vezes, pode ser o estado de outra coisa. Neste caso, ele muda o estado do repositório, e é isso que você deve ser o teste.

Este é chamado de teste Inderect Saídas , em vez do mais normal Saídas diretas (valores de retorno).

O truque é testes de unidade de gravação de modo que eles não quebram com muita freqüência. Ao usar Mocks, é fácil acidentalmente escrever testes Overspecified , que é porque a maioria Mocks dinâmico (como MOQ) como padrão Stub Modo, onde ele realmente não importa o quão muitas vezes você chamar um determinado método.

Tudo isso, e muito mais, é explicado no excelente xUnit test .

Um método que não retorna nenhum resultado ainda muda o estado da sua candidatura. Seu teste de unidade, neste caso, deve ser testar se o novo estado é como pretendido.

"o teste de unidade seria um fracasso, mas ele provavelmente não iria quebrar a sua aplicação"

Este é - na verdade - realmente importante saber. Pode parecer chato e trivial, mas quando alguém começa mantendo seu código, eles podem ter feito uma péssima mudança para salvar e (improvavelmente) quebrado o aplicativo.

O truque é dar prioridade.

Test as coisas importantes em primeiro lugar. Quando as coisas são lentas, adicionar testes para coisas triviais.

Quando não há uma afirmação em um método, que são essencialmente afirmando que exceções não são lançadas.

Eu também estou lutando com a questão de como testar myMethod public void (). Eu acho que se você decidir adicionar um valor de retorno para a capacidade de teste, o valor de retorno deve representar todos os fatos salientes necessárias para ver o que mudou sobre o estado da aplicação.

public void myMethod()

se torna

 public ComplexObject myMethod() { 
 DoLotsOfSideEffects()
 return new ComplexObject { rows changed, primary key, value of each column, etc };
 }

e não

public bool myMethod()  
  DoLotsOfSideEffects()
  return true;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top