Devo inicializar campos de classe em declarações como esta?
public class SomeTest extends TestCase
{
private final List list = new ArrayList();
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
Ou em setUp () assim?
public class SomeTest extends TestCase
{
private List list;
@Override
protected void setUp() throws Exception
{
super.setUp();
this.list = new ArrayList();
}
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
Costumo usar o primeiro formulário porque é mais conciso e me permite usar os campos finais. Se eu não precisar usar o método setUp () para instalação, ainda devo usá-lo e por quê?
Esclarecimento: O
JUnit instancia a classe de teste uma vez por método de teste. Isso significa list
que será criado uma vez por teste, independentemente de onde eu o declare. Isso também significa que não há dependências temporais entre os testes. Portanto, parece que não há vantagens em usar setUp (). No entanto, a FAQ do JUnit tem muitos exemplos que inicializam uma coleção vazia em setUp (), então acho que deve haver um motivo.
Respostas:
Se você está se perguntando especificamente sobre os exemplos nas Perguntas frequentes da JUnit, como o modelo de teste básico , acho que a melhor prática a ser mostrada é que a classe em teste deve ser instanciada no seu método setUp (ou em um método de teste) .
Quando os exemplos JUnit criam um ArrayList no método setUp, todos eles testam o comportamento desse ArrayList, com casos como testIndexOutOfBoundException, testEmptyCollection e similares. A perspectiva é de alguém escrever uma classe e garantir que ela funcione corretamente.
Você provavelmente deve fazer o mesmo ao testar suas próprias classes: crie seu objeto em setUp ou em um método de teste, para que você possa obter uma saída razoável se a interromper mais tarde.
Por outro lado, se você usa uma classe de coleção Java (ou outra classe de biblioteca) no seu código de teste, provavelmente não é porque você deseja testá-lo - é apenas parte do equipamento de teste. Nesse caso, você pode assumir com segurança que ele funciona como pretendido, portanto, inicializá-lo na declaração não será um problema.
Pelo que vale, eu trabalho em uma base de código razoavelmente grande, com vários anos de idade e desenvolvida por TDD. Habitualmente, inicializamos as coisas em suas declarações no código de teste e, no ano e meio em que estive neste projeto, isso nunca causou um problema. Portanto, há pelo menos alguma evidência anedótica de que é uma coisa razoável a se fazer.
fonte
Comecei a me cavar e encontrei uma vantagem em potencial do uso
setUp()
. Se alguma exceção for lançada durante a execução desetUp()
, o JUnit imprimirá um rastreamento de pilha muito útil. Por outro lado, se uma exceção for lançada durante a construção do objeto, a mensagem de erro simplesmente diz que o JUnit não conseguiu instanciar o caso de teste e você não vê o número da linha onde ocorreu a falha, provavelmente porque o JUnit usa reflexão para instanciar o teste Aulas.Nada disso se aplica ao exemplo de criação de uma coleção vazia, pois isso nunca será lançado, mas é uma vantagem do
setUp()
método.fonte
Além da resposta de Alex B.
É necessário usar o método setUp para instanciar recursos em um determinado estado. Fazer isso no construtor não é apenas uma questão de tempos, mas, devido à maneira como o JUnit executa os testes, cada estado de teste será apagado após a execução de um.
O JUnit primeiro cria instâncias do testClass para cada método de teste e começa a executar os testes após a criação de cada instância. Antes de executar o método de teste, seu método de configuração é executado, no qual algum estado pode ser preparado.
Se o estado do banco de dados fosse criado no construtor, todas as instâncias instanciariam o estado db logo após o outro, antes de executar cada teste. A partir do segundo teste, os testes seriam executados com um estado sujo.
Ciclo de vida das JUnits:
Com alguns registros em um teste com dois métodos de teste, você obtém: (number é o hashcode)
fonte
@BeforeClass
em JUnit 4.Na JUnit 4:
@Before
método, para detectar falhas.final
questões de brevidade e para marcar os campos exatamente como indicado na pergunta,@Before
, usar , para detectar falhas.@BeforeClass
, mas tenha cuidado com as dependências entre os testes.A inicialização de um
@Before
método ou método de teste permite obter melhores relatórios de erros sobre falhas. Isso é especialmente útil para instanciar a classe em teste (que você pode interromper), mas também é útil para chamar sistemas externos, como acesso ao sistema de arquivos ("arquivo não encontrado") ou conectar-se a um banco de dados ("conexão recusada").É aceitável ter um padrão simples e sempre usar
@Before
(erros claros, mas detalhados) ou sempre inicializar na declaração (conciso, mas gera erros confusos), já que regras de codificação complexas são difíceis de seguir, e isso não é grande coisa.A inicialização de in
setUp
é uma relíquia do JUnit 3, onde todas as instâncias de teste foram inicializadas rapidamente, o que causa problemas (velocidade, memória, esgotamento de recursos) se você fizer uma inicialização cara. Portanto, a melhor prática era fazer uma inicialização carasetUp
, que só era executada quando o teste foi executado. Isso não se aplica mais, portanto, é muito menos necessário usá-losetUp
.Isso resume várias outras respostas que enterram o lede, especialmente por Craig P. Motlin (pergunta em si e resposta automática), Moss Collum (classe em teste) e dsaff.
fonte
No JUnit 3, seus inicializadores de campo serão executados uma vez por método de teste antes de qualquer teste ser executado . Desde que seus valores de campo sejam pequenos na memória, demore pouco tempo de configuração e não afete o estado global, o uso de inicializadores de campo é tecnicamente adequado. No entanto, se isso não acontecer, você pode acabar gastando muita memória ou tempo configurando seus campos antes da execução do primeiro teste e possivelmente até ficando sem memória. Por esse motivo, muitos desenvolvedores sempre definem valores de campo no método setUp (), onde é sempre seguro, mesmo quando não é estritamente necessário.
Observe que no JUnit 4, a inicialização do objeto de teste acontece logo antes da execução do teste, portanto, o uso de inicializadores de campo é um estilo mais seguro e recomendado.
fonte
No seu caso (criando uma lista), não há diferença na prática. Mas geralmente é melhor usar setUp (), porque isso ajudará a Junit a relatar exceções corretamente. Se ocorrer uma exceção no construtor / inicializador de um Teste, isso será uma falha no teste . No entanto, se ocorrer uma exceção durante a instalação, é natural pensar nisso como um problema na configuração do teste, e o junit o reporta adequadamente.
fonte
Prefiro a legibilidade primeiro, que na maioria das vezes não usa o método de instalação. Faço uma exceção quando uma operação de configuração básica demora muito tempo e é repetida em cada teste.
Nesse ponto, movo essa funcionalidade para um método de configuração usando a
@BeforeClass
anotação (otimizar posteriormente).Exemplo de otimização usando o
@BeforeClass
método de instalação: Eu uso o dbunit para alguns testes funcionais do banco de dados. O método de configuração é responsável por colocar o banco de dados em um estado conhecido (muito lento ... 30 segundos - 2 minutos, dependendo da quantidade de dados). Carrego esses dados no método de instalação anotado@BeforeClass
e, em seguida, executo de 10 a 20 testes no mesmo conjunto de dados, em vez de recarregar / inicializar o banco de dados dentro de cada teste.O uso do Junit 3.8 (estendendo o TestCase como mostrado no seu exemplo) requer a criação de um pouco mais de código do que apenas a adição de uma anotação, mas a "executar uma vez antes da configuração da classe" ainda é possível.
fonte
Como cada teste é executado de forma independente, com uma nova instância do objeto, não faz muito sentido que o objeto Teste tenha qualquer estado interno, exceto aquele compartilhado entre
setUp()
e um teste individual etearDown()
. Esse é um dos motivos (além dos motivos apresentados por outros): é bom usar osetUp()
método.Nota: É uma má idéia para um objeto de teste JUnit manter o estado estático! Se você usar variável estática em seus testes para outras finalidades que não sejam de rastreamento ou diagnóstico, estará invalidando parte do objetivo do JUnit, que é o de que os testes possam (pode) ser executados em qualquer ordem, cada teste executando com um estado fresco e limpo.
As vantagens de usar
setUp()
é que você não precisa recortar e colar o código de inicialização em todos os métodos de teste e que não possui código de configuração de teste no construtor. No seu caso, há pouca diferença. Apenas a criação de uma lista vazia pode ser feita com segurança, como você a mostra ou no construtor, pois é uma inicialização trivial. No entanto, como você e outras pessoas apontaram, qualquer coisa que possa gerar umException
deve ser feitasetUp()
para que você obtenha o despejo da pilha de diagnóstico se ele falhar.No seu caso, onde você está apenas criando uma lista vazia, eu faria da mesma maneira que você está sugerindo: Atribua a nova lista no ponto da declaração. Especialmente porque dessa maneira você tem a opção de marcá-la
final
se isso fizer sentido para a sua classe de teste.fonte
final
é mencionada na pergunta embora.Os valores constantes (usados em equipamentos ou afirmações) devem ser inicializados em suas declarações e
final
(como nunca mudam)o objeto em teste deve ser inicializado no método de configuração, pois podemos definir as coisas. É claro que não podemos definir algo agora, mas podemos defini-lo mais tarde. Instanciar no método init facilitaria as alterações.
As dependências do objeto em teste, se elas forem zombadas, nem devem ser instanciadas por você: hoje, as estruturas de simulação podem instancia-lo por reflexão.
Um teste sem dependência para zombar pode parecer com:
Um teste com dependências para isolar pode se parecer com:
fonte