IEA - Uma estratégia de teste baseada em arquivos para transformações de documentos

IEA - Uma estratégia de teste baseada em arquivos para transformações de documentos

Por 23 de Fevereiro de 2017Engenharia

por Douglas Campbell, Engenheiro Principal

I/E/A - Entrada/Esperado/Actual

Se você puder fornecer implementações para o conjunto de funções abaixo,

// defines how to go from file to an instance of IN
abstract IN loadInput(File input);

// defines how to go from file to OUT instances
// throw FNF whenever there’s no expected file.
abstract OUT loadOutput(File expected) throws FileNotFoundException;

// invoked upon missing expected file or if actual != expected
abstract void storeResult(OUT result, File resultFile);

muito pode ser feito para tirar a drogaria das transformações de documentos de teste e manter um conjunto robusto de testes.

Em resumo, torna-se trivial escrever casos de teste como arquivos em vez de funções.

Eu prefiro muito mais esta abordagem do que testar a transformação de documentos do que usar o código de teste. Primeiro, um pouco de fundo.

Antecedentes

Tanto do código que escrevi ao longo dos anos tem no seu núcleo a transformação de documentos de um formato em outro. Por documentos, estou falando de qualquer variedade de json, xml, avro, tab delimitado, yaml, qualquer coisa - qualquer coisa e tudo para qualquer coisa e tudo e de volta novamente.

Quando se pede para codificar coisas como esta, muitos olhos do dev simplesmente rolam para o horror de escrever algo tão trivial como cartografar um campo para outro, dar-lhe um casquilho superior, fundi-lo com outro valor lido a partir de alguma fonte de dados externa, e depois sair para outra representação.

Essa nova representação pode ter pouca semelhança com o documento inicial. Essa é a natureza da besta.

Em suma, os requisitos que impulsionam as transformações de dados são completamente arbitrários!

Acho que esta é a razão pela qual alguns devs detestam estas coisas. Eles tomam atalhos e atiram coisas para o código de teste que se parecem com isto...

//CHECKSTYLE:OFF
private static final String CLICK = "a horrendously ugly line of input from an access log";
//CHECKSTYLE:ON

E quando chegar a hora de testar uma "impressão" adivinhe o que acontece. Ugh - testar a entrada em linha como variáveis de string. Sentido de aranha imediatamente activado após a supressão do checkstyle!

Uma coisa que aprendi é que onde quer que haja medo e evasão, é exactamente onde é necessária alguma preguiça excessivamente enérgica. Afaste-se. Simplifique tudo e livre-se de resmas e resmas de lógica e ou código duplicados. Escreva uma função para correr sobre uma pasta inteira cheia de testes

// test folder of tests and fail entire run if any fail.
public void testFolder(File testfolder, Function<IN, OUT> converter) {

    for (File test: testfolder.listFiles(testFileFilter)) {
        if (!testSingle(test, converter)) {
           fail("expected != actual - actual " +
           "results saved in .actual file");
        };
    }
}

Então e este testeFunção única? Muito simples com as três funções definidas no início do blog.

// test a single test
private boolean testSingle(File test, Function converter) {
    IN input = loadInput(test);
    OUT actual = converter.apply(input);
    OUT expected = null;

    // only create if no expected file or result is different.
    File actualFile = new File(test.getParent(),
                               test.getName() + ".actual");

    try {
        expected = loadOutput(new File(test.getParent(),
                                       test.getName()
                                       + ".expected"));

    } catch (FileNotFoundException ex) {
        // we haven't got expected file - no biggie
        // we can turn this into an expected file once
        // satisfied with it.
        storeResult(actual, actualFile);
    }
    return false;

    // we've got something to compare
    if (!actual.equals(expected)) {
        // fail and save the actual file for command
        // line diffing
        storeResult(actual, actualFile);
        return false;
    }

    return true;
}

Diversos benefícios desta abordagem

Para documentos baseados em texto e ou ascii, a utilidade dif está imediatamente disponível para comparar falhas nos testes

Você não precisa escrever código de teste para gerar qual é o resultado esperado. Basta adicionar o seu registro de amostra à pasta de testes, executar os testes e a saída real é gerada para um novo arquivo com extensão .real

Você tem uma maneira imediata de executar o seu código sobre os registros que lhe causaram problemas na produção. Mais uma vez, coloque o registro problemático em sua pasta de teste e execute o teste.

Se a sua equipa decidir construir um novo conversor ou usar uma biblioteca json diferente, todos os seus testes são expressos como ficheiros independentes do idioma. Você pode levá-los adiante.

Coisas para ir logo à frente

Primeiro, tenha cuidado para tornar a sua lógica de transformação sem estados. Essencialmente, as transformações de documentos que envolvem chamadas fora de processo precisam ser retrabalhadas a fim de separar a recuperação de dados brutos do que é feito a ela.

Em segundo lugar, comece a fazer isso logo no início do ciclo de vida do módulo de código ou aplicativo. Os apetites são normalmente muito escassos para dar voltas e voltar a trabalhar nos velhos e nojentos testes.

Próximo passo

Um próximo passo para nós é empacotar isto como um pacote de teste de código aberto. Quem sabe, isso pode acontecer ainda mais cedo se tivermos um pouco de interesse ?

Sobre ShareThis

ShareThis has unlocked the power of global digital behavior by synthesizing social share, interest, and intent data since 2007. Impulsionado pelo comportamento do consumidor em mais de três milhões de domínios globais, ShareThis observa acções em tempo real de pessoas reais em destinos digitais reais.

Subscreva a nossa Newsletter

Receba as últimas notícias, dicas e actualizações

Assine

Conteúdo relacionado