Como o Kotlin pode ajudar nos testes de API: o caso do Rusfinance Bank





O título Kotlin afirmava estar mais associado ao desenvolvimento do Android, mas por que não experimentar? Com sua ajuda, encontramos uma maneira de simplificar levemente a automação do teste da API de um de nossos serviços, além de facilitar o trabalho de testadores que não estão familiarizados com a programação e as nuances da linguagem Java.



O que estamos fazendo? Estamos desenvolvendo um serviço para enviar questionários de corretagem para calcular e receber uma decisão sobre eles. E, apesar de ser uma solução bancária, o desenvolvimento é realizado por uma pequena equipe de scrum, na qual 1-2 especialistas estão envolvidos nos testes, dependendo da carga e da situação no projeto.



De acordo com o corte, falaremos sobre os resultados de nossos experimentos, que transferimos com prazer para a produção.



Sem rosto



Nosso serviço foi desenvolvido para integrar-se à interface dos parceiros e não possui uma interface de usuário própria. Portanto, nesse caso, testar a API diretamente é a única opção disponível. Embora os testes de API tenham várias vantagens, mesmo com uma interface:



  • permitir que você comece a testar já na fase de desenvolvimento de serviços;
  • simplifique a localização de erros;
  • geralmente reduz o tempo de teste.


Nosso serviço inclui um conjunto de APIs para transferir os dados do questionário do cliente para cálculo e para obter uma solução para um empréstimo de carro. As seguintes verificações podem ser distinguidas como as principais tarefas de teste de alto nível:



  • formato de campos e parâmetros;
  • correção de códigos de status e mensagens de erro;
  • campos obrigatórios e lógica de serviço.






Momento crucial



A equipe preparou o MVP do serviço em um tempo muito curto e os testes automatizados foram originalmente escritos pelo desenvolvedor do produto. Era mais rápido e mais conveniente incluir autotestes no projeto, portanto, inicialmente eles estavam intimamente relacionados ao seu código e baseavam-se na pilha Java, com garantia REST e na estrutura de teste TestNG.



Com o desenvolvimento do projeto, o envolvimento dos testadores no processo de automação aumentou. No momento, as tarefas de suporte e atualização de autotestes pertencem inteiramente ao departamento de testes. Nesse sentido, tornou-se necessário ajustar a abordagem da automação - para simplificar os testes o máximo possível e torná-los independentes do código principal. E, assim, resolver as dificuldades decorrentes:



  • a comunicação com o código torna os testes mais vulneráveis ​​a qualquer alteração no projeto, exige muito trabalho para manter o desempenho;
  • relacionamentos complexos aumentam o tempo para encontrar informações e investigar erros;
  • É difícil envolver novos funcionários do departamento de testes no trabalho com código Java, requer treinamento dos testadores e uma quantidade significativa de tempo para entrar no projeto.


Portanto, decidimos alterar a abordagem de teste e formulamos os seguintes requisitos para novas ferramentas:



  • compatibilidade total com Java, que permite reescrever verificações em etapas, enquanto continua a trabalhar com testes antigos;
  • código simples e intuitivo;
  • linguagem livre e estável;
  • seleção de autotestes em um projeto separado.




O que Kotlin tem a ver com isso



A língua Kotlin atende às nossas necessidades, tanto quanto possível.







Além da total compatibilidade com Java no Kotlin, estávamos interessados ​​nos seguintes recursos:



  • a concisão da linguagem torna o código claro e fácil de ler;
  • açúcar sintático;
  • código intuitivo e fácil entrada de especialistas no projeto;
  • a capacidade de transferir autotestes de Java para Kotlin de forma gradual e indolor, parcialmente se necessário.


Obviamente, também existem desvantagens, especialmente em comparação com Java. Primeiro, uma comunidade relativamente pequena: encontrar ajuda e respostas para perguntas sobre Java é muito mais fácil do que com o Kotlin. Em segundo lugar, em geral, Java é uma linguagem mais universal, com mais recursos e um grande número de desenvolvimentos e bibliotecas.



Mas, francamente, para fins de teste, não precisamos de recursos tão extensos que apenas o Java possa fornecer. Portanto, preferimos a simplicidade e brevidade do Kotlin.



Das palavras às ações



Como resultado de uma transição parcial para um novo idioma, recebemos um ganho notável nos custos de mão de obra para especialistas, uma simplificação significativa do código e uma redução no seu volume. Isso é visto claramente em exemplos específicos de testes de nosso serviço para processar perfis de corretagem.



No Kotlin, você pode inicializar um objeto de solicitação com uma linha de código. Por exemplo, a classe ApplicationDTO (para enviar um questionário para a solução) e o ErrorDTO (erros provenientes do serviço) têm a seguinte aparência:







Kotlin permite definir valores de campo durante a inicialização. Isso economiza muito tempo ao escrever testes: ao criar um objeto, os campos já estão preenchidos com dados válidos, apenas alteramos os valores que se referem à verificação atual.



A anotação JsonIgnoreProperties permite que você não especifique todos os campos de uma classe se eles não forem necessários para testes e não precisarem ser verificados. Se for recebido um campo que não esteja especificado na descrição, o teste não falhará com um erro.



O ponto de interrogação no tipo de uma variável indica que em algum momento ela pode ser nula. Mas ao usar uma variável, isso precisará ser levado em consideração e processado. Finalmente, diferentemente dos testes Java, o NullPointerException pode ser evitado normalmente aqui.



Vamos ilustrar com um exemplo simples de verificação de erro para um login incorreto:



class ApplicationTests {

    val DEFAULT_LOGIN = "consLogin"
    val ERROR_CODE = "3"
    val BASE_URI = "https://base_url.com"

    @Test
    fun incorrectLogin() {
        val incorrectLogin = DEFAULT_LOGIN + "INCORRECT";
        val res = given()
                .spec(spec)
                .body(ApplicationDTO)
                .`when`()
                .post(endpointApplication(incorrectLogin)
                        .then()
                        .statusCode(400)
                        .extract().`as`(ErrorDTO::class.java)
                        assertThat(res.error_message).containsIgnoringCase("    ")
                        assertThat(res.error_code).isEqualToIgnoringCase(ERROR_CODE)
    }

    companion object{
        private var spec: RequestSpecification? = null

        @JvmStatic
        @BeforeClass
        fun initSpec() {
            spec = RequestSpecBuilder()
                    .setContentType(ContentType.JSON)
                    .setBaseUri(BASE_URI)
                    .addFilter(ResponseLoggingFilter())
                    .addFilter(RequestLoggingFilter())
                    .build()
        }
    }
}


Criamos uma especificação para consultas no BeforeClass, que reutilizamos em todos os testes dessa classe. Jackson serializa e desserializa objetos json, o que simplifica as coisas: você não precisa trabalhar com eles como com strings, por isso, o número de erros é reduzido significativamente.







Com o Kotlin, reduzimos significativamente a quantidade de código, o que significa que facilitamos a vida de "escritores" e "leitores". A classe ApplicationDTO já contém um construtor e alguns outros métodos (hashCode (), copy () etc.) - não precisamos "sobrecarregar" o código com eles e os desenvolvedores iniciantes de autoteste não são distraídos por eles. Eles não precisam ser atualizados em caso de alterações, o que reduz o tempo para fazer edições nos testes.



Também é muito conveniente que o Kotlin suporte argumentos nomeados - o código é muito fácil de ler e não há necessidade de escrever setters para as classes de objetos json.



Experimente coisas novas de graça



Gostaria de observar a abertura e transparência do Kotlin e de todas as bibliotecas que usamos, o que simplifica bastante o trabalho e expande as possibilidades de experimentar e introduzir novas abordagens. Concordo, é sempre mais fácil experimentar coisas novas de graça e, em caso de falha, retornar às práticas antigas.



No futuro, planejamos desenvolver uma nova abordagem e escalá-la para outros projetos, converter o restante dos testes de API e da interface do usuário para o Kotlin.



PS: Apesar do Kotlin estar associado principalmente ao desenvolvimento do Android, o escopo de seu uso, como você entende, não se limita a isso. Reduzindo o tempo gasto na escrita de código, sua simplicidade e concisão ajudarão a reduzir os custos de mão-de-obra na solução de muitos problemas. Se tivermos novos casos com o Kotlin, definitivamente falaremos sobre eles.aqui .



All Articles