Eu gostaria de testar uma aula abstrata. Claro, eu posso escrever manualmente uma simulação que herda da classe.
Posso fazer isso usando uma estrutura de zombaria (estou usando o Mockito) em vez de criar manualmente minha zombaria? Quão?
java
unit-testing
mocking
abstract-class
mockito
ripper234
fonte
fonte
SomeAbstract spy = spy(SomeAbstract.class);
mock(MyAbstractClass.class, withSettings().useConstructor(arg1, arg2).defaultAnswer(CALLS_REAL_METHODS))
Respostas:
A sugestão a seguir permite testar classes abstratas sem criar uma subclasse "real" - a Mock é a subclasse.
use
Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS)
e zombe de quaisquer métodos abstratos que são chamados.Exemplo:
Nota: A vantagem desta solução é que você não precisa implementar os métodos abstratos, desde que eles nunca sejam invocados.
Na minha opinião sincera, isso é mais legal do que usar um espião, já que um espião exige uma instância, o que significa que você deve criar uma subclasse instável da sua classe abstrata.
fonte
Se você só precisar testar alguns dos métodos concretos sem tocar em nenhum dos resumos, poderá usá-lo
CALLS_REAL_METHODS
(consulte a resposta de Morten ), mas se o método concreto em teste chamar alguns dos resumos ou métodos de interface não implementados, isso não funcionará. - Mockito reclamará "Não é possível chamar o método real na interface java".(Sim, é um design ruim, mas algumas estruturas, como o Tapeçaria 4, meio que o impõem a você.)
A solução alternativa é reverter essa abordagem - use o comportamento de simulação comum (isto é, tudo é ridicularizado / stubbed) e use
doCallRealMethod()
para chamar explicitamente o método concreto em teste. Por exemploAtualizado para adicionar:
Para métodos não nulos, você precisará usar
thenCallRealMethod()
, por exemplo:Caso contrário, Mockito reclamará de "stubbing inacabado detectado".
fonte
Você pode conseguir isso usando um espião (use a versão mais recente do Mockito 1.8+).
fonte
As estruturas de simulação são projetadas para facilitar a simulação de dependências da classe que você está testando. Quando você usa uma estrutura de zombaria para zombar de uma classe, a maioria das estruturas cria dinamicamente uma subclasse e substitui a implementação do método pelo código para detectar quando um método é chamado e retornar um valor falso.
Ao testar uma classe abstrata, você deseja executar os métodos não abstratos do Subject Under Test (SUT), para que uma estrutura de simulação não seja o que você deseja.
Parte da confusão é que a resposta à pergunta a que você vinculou criou um escárnio que se estende de sua classe abstrata. Eu não chamaria essa classe de zombaria. Uma simulação é uma classe usada como substituta de uma dependência, é programada com expectativas e pode ser consultada para verificar se essas expectativas são atendidas.
Em vez disso, sugiro definir uma subclasse não abstrata de sua classe abstrata em seu teste. Se isso resultar em muito código, isso pode ser um sinal de que é difícil estender sua classe.
Uma solução alternativa seria tornar o seu caso de teste abstrato, com um método abstrato para criar o SUT (em outras palavras, o caso de teste usaria o padrão de design do Método de Modelo ).
fonte
Tente usar uma resposta personalizada.
Por exemplo:
Ele retornará a simulação para métodos abstratos e chamará o método real para métodos concretos.
fonte
O que realmente me faz sentir mal ao zombar de classes abstratas é o fato de que nem o construtor padrão YourAbstractClass () é chamado (falta super () no mock) nem parece haver alguma maneira no Mockito de inicializar as propriedades de simulação padrão (por exemplo, propriedades da lista com ArrayList ou LinkedList vazio).
Minha classe abstrata (basicamente o código fonte da classe é gerada) NÃO fornece uma injeção de setter de dependência para os elementos da lista, nem um construtor onde inicializa os elementos da lista (que tentei adicionar manualmente).
Somente os atributos da classe usam a inicialização padrão: private List dep1 = new ArrayList; lista particular dep2 = new ArrayList
Portanto, NÃO há como zombar de uma classe abstrata sem usar uma implementação de objeto real (por exemplo, definição de classe interna na classe de teste de unidade, substituindo métodos abstratos) e espionando o objeto real (que faz a inicialização apropriada do campo).
Pena que apenas o PowerMock ajudaria aqui ainda mais.
fonte
Supondo que suas classes de teste estejam no mesmo pacote (em uma raiz de origem diferente) das classes em teste, você pode simplesmente criar o mock:
e chame os métodos que você deseja testar, como faria com qualquer outro método.
Você precisa fornecer expectativas para cada método chamado com a expectativa de qualquer método concreto chamado super método - não sei como você faria isso com o Mockito, mas acredito que isso é possível com o EasyMock.
Tudo o que isso está fazendo é criar uma instância concreta
YouClass
e poupar o esforço de fornecer implementações vazias de cada método abstrato.Como um aparte, muitas vezes acho útil implementar a classe abstrata em meu teste, onde ela serve como exemplo de implementação que eu teste por meio de sua interface pública, embora isso dependa da funcionalidade fornecida pela classe abstrata.
fonte
Você pode estender a classe abstrata com uma classe anônima em seu teste. Por exemplo (usando o Junit 4):
fonte
Mockito permite zombar de classes abstratas por meio da
@Mock
anotação:A desvantagem é que ele não pode ser usado se você precisar de parâmetros do construtor.
fonte
Você pode instanciar uma classe anônima, injetar suas zombarias e testá-la.
Lembre-se de que a visibilidade deve ser
protected
da propriedademyDependencyService
da classe abstrataClassUnderTest
.fonte
Os PowerMock
Whitebox.invokeMethod(..)
podem ser úteis nesse caso.fonte