Junit4: O método @Parameters é executado antes da inicialização de @ClassRule. Poderia ser o caminho de volta?

Criado em 2 mai. 2013  ·  9Comentários  ·  Fonte: junit-team/junit4

Eu tenho o seguinte problema (usando _junit 4.11_):

    <strong i="6">@ClassRule</strong>
    public static TemporaryFolder tmp = new TemporaryFolder();
    ...
    <strong i="7">@Parameters</strong>
    public static Collection<Object[]> data() throws Exception {
        return java.util.Arrays.asList(new Object[][] {
            {0, tmp.getRoot().getPath()}
        });
    }

Isso resulta em initializationError

java.lang.IllegalStateException: the temporary folder has not yet been created
    at org.junit.rules.TemporaryFolder.getRoot(TemporaryFolder.java:127)

Assim, parece que o método _@Parameters_ é executado antes da fase de inicialização _ClassRule_, o que torna os cenários acima um pouco complicados.

Comentários muito úteis

Solução alternativa atual:

    protected static TemporaryFolder initStaticTemp() {
        try {
            return new TemporaryFolder() { { before(); } };
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    public static TemporaryFolder tmp = initStaticTemp();

    <strong i="6">@AfterClass</strong>
    public static cleanup() throws Exception {
        tmp.delete();
    }

Funciona, mas precisa daquela limpeza manual...

Todos 9 comentários

Solução alternativa atual:

    protected static TemporaryFolder initStaticTemp() {
        try {
            return new TemporaryFolder() { { before(); } };
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    public static TemporaryFolder tmp = initStaticTemp();

    <strong i="6">@AfterClass</strong>
    public static cleanup() throws Exception {
        tmp.delete();
    }

Funciona, mas precisa daquela limpeza manual...

+1

Pensando um pouco, acho que uma boa maneira de implementar isso seria introduzir uma anotação para isso:

<strong i="7">@Parameters</strong>
<strong i="8">@AfterClassRules</strong>
public Object[][] generateParameters() {
    // do stuff
}

Isso garantiria que ambas as variantes ainda fossem utilizáveis ​​e que o código existente não fosse quebrado. Se este design for aceitável para os mantenedores, eu começaria a trabalhar em um pull request para isso.

Estou escrevendo um comentário adicional porque não tenho certeza se uma atualização em um comentário aciona uma notificação.

O design proposto no meu comentário anterior seria aceitável para os mantenedores? Se assim for, eu começaria a trabalhar em um pull-request.

Há um problema de arquitetura bastante difícil aqui: o JUnit promete a executores como o Eclipse que ele pode enumerar quantos testes existem antes que qualquer um dos testes seja executado, mas também deseja minimizar quaisquer recursos consumidos durante essa fase de planejamento. Então, realmente queremos saber quantos parâmetros existirão antes de, por exemplo, criar qualquer pasta temporária ou fazer as coisas ainda mais drásticas que aparecem nas ClassRules, como iniciar servidores.

Talvez minha resposta favorita seja habilitar algo como @DataPoints em Theories: pode haver campos estáticos ou métodos estáticos prefixados com @ParameterSet , que são unidos para fazer o conjunto de parâmetros completo. Então seu exemplo seria:

@ClassRule public static TemporaryFolder tmp = new TemporaryFolder();
@ParameterSet public static Object[] first = new Object[] { 0 };
@ParameterSet public static Object[] segundo() {
return new Object[] { tmp.getRoot().getPath(); }
}

O ponto aqui é que poderíamos contar o método "segundo" sem realmente executá-lo.

O que você acha?

Hm, acho que agora que penso nisso, o problema é na verdade mais um cheiro no meu código de teste. Estou me conectando a um serviço remoto e executando testes dependendo de como ele está configurado. Em vez disso, eu provavelmente deveria apenas corrigir a configuração esperada no meu teste.

Aqui está o teste em que originalmente enfrentei o problema: CryptoAppExecReturnCodeTest.java

@dsaff Vou pensar um pouco sobre sua sugestão. A impressão inicial é: dividir os pares em arrays separados requer um cuidado especial com as posições dos elementos (um pouco propenso a erros). Então eu posso acabar enchendo _primeiro_ com algumas coisas fictícias (apenas mantendo o número de elementos); e em _second_ - gostaria de manter os elementos do par próximos um do outro:

{ 0, tmp...getPath() },
{ 1, ... }

Existe mais alguma coisa que os corredores precisam além do número de testes? (Por exemplo - talvez nomes de teste?)

@javornikolov , acabei de perceber que li errado sua postagem inicial e, portanto, minha resposta provavelmente foi confusa. Eu estava lendo seu teste como duas instanciações diferentes de uma classe de teste que é construída com um parâmetro; agora que li novamente, é na verdade uma instanciação de uma classe de teste que é construída com dois parâmetros. Para ajustar minha proposta então, o código sugerido seria:

<strong i="7">@ClassRule</strong> public static TemporaryFolder tmp = new TemporaryFolder();
<strong i="8">@ParameterSet</strong> public static Object[] only() {
return new Object[] { 0, tmp.getRoot().getPath(); }
}

Espero que isso torne minha intenção mais clara; desculpe minha confusão inicial.

(passando por alguns bugs antigos)

Talvez devêssemos renomear esse problema como "Ativar algo como @DataPoints em Teorias"?

(passando por alguns bugs antigos)

Talvez devêssemos renomear esse problema como "Ativar algo como @DataPoints em Teorias"?

Eu diria que o problema é poder usar recursos Rule na lista de parâmetros para testes parametrizados. A abordagem com @ParameterSet proposta por @dsaff me parece viável (supondo que as avaliações aconteçam em tal sequência que o problema original seja resolvido).
Mas se "Algo como @DataPoints" estiver claro o suficiente e não houver risco de divergir em alguma direção que não cubra o cenário original: OK para mim.
A razão pela qual prefiro testes parametrizados em vez de teorias (que usam DataPoints) é que os resultados destes últimos não são relatados independentemente para cada conjunto de parâmetros, e essa primeira falha aborta a execução dos parâmetros subsequentes.

Esta página foi útil?
0 / 5 - 0 avaliações