O estado atual dos testes com o Couchbase exige que você use algo como CouchbaseMockou simular a API por conta própria, ou ter um Servidor Couchbase iniciada antes de executar esses testes. A simulação funciona, mas não está realmente testando o Couchbase. Pode ser bom para o teste de unidade, mas descartado para testes de integração. Ter uma instância do Couchbase iniciada é melhor. E, embora isso funcione, não é uma solução fácil e industrializável. Você não pode simplesmente executar uma compilação em qualquer máquina e esperar que a coisa funcione. Isso exigiria que todos instalassem o Couchbase Server e o mantivessem on-line o tempo todo. E, embora isso me deixasse muito feliz, é improvável que aconteça.
Portanto, outra abordagem poderia ser fazer com que seu teste fosse responsável por iniciar o banco de dados. Você certamente poderia incluir isso em seus scripts de compilação. O Maven, o Gradle e outros podem lhe fornecer ganchos no ciclo de vida da compilação. Dessa forma, você poderia iniciar e parar o banco de dados antes de executar o teste de integração. Mas isso adicionaria alguma dependência à ferramenta de compilação que você está usando. Para ser independente da ferramenta de compilação, você precisa iniciar e parar o banco de dados a partir do seu código.
Outro problema que você encontrará ao configurar isso é que provavelmente terá de dar suporte a diferentes sistemas operacionais. Iniciar e parar o BD será diferente se você estiver executando Linux, Windows ou OSX. E isso pressupõe que o BD já esteja instalado na máquina. Para evitar esses problemas, você precisa de um tempo de execução comum a todas essas plataformas. E isso é algo que Docker pode lhe dar.
O Docker atuará como um armazenamento binário distribuído para baixar uma imagem para qualquer banco de dados que você desejar. E a maneira de gerenciar o contêiner do Docker é idêntica em todas as plataformas. Ele oferece uma alternativa superleve às VMs e, embora possa causar problemas em alguns casos particulares na produçãoÉ absolutamente perfeito para esse caso de uso.
As grandes pessoas por trás Contêineres de teste entendemos isso e estamos propondo uma solução integrada para todos os problemas acima.
TestContainers é uma biblioteca Java que oferece suporte a testes JUnit, fornecendo instâncias leves e descartáveis de bancos de dados comuns, navegadores da Web Selenium ou qualquer outra coisa que possa ser executada em um contêiner do Docker.
Atualmente, o TestContainers é apenas Java, mas esse conceito pode ser adaptado a qualquer linguagem que tenha um cliente Docker. Vamos ver como isso funciona com um projeto Java simples.
Como testar a amostra de cerveja
Escrevi um projeto mostrando tudo o que você precisa para usar Contêineres de teste e Couchbase. Para que esse projeto funcione, você precisará que o Docker seja executado na máquina que estiver executando o teste. Para garantir que ele funcione, abra um terminal e digite informações da plataforma
. Isso deve lhe dar uma resposta como esta:
Agora vamos escrever o teste. Podemos começar definindo um Contêiner genérico com uma @ClassRule. Isso significa que o contêiner será configurado antes da execução dos testes e removido após os testes. Você pode usar @Rule se quiser que isso aconteça para cada teste da classe que estiver executando. Esse GenericContainer requer um nome. Esse é o identificador completo, nome e tag, da imagem do Docker que você deseja usar. Aqui estou usando uma imagem personalizada que inicia o Couchbase Server com a amostra de cerveja pré-carregada. Você pode criar essa imagem digitando docker build -t mycouchbase .
na raiz do projeto.
Em seguida, você pode configurar a lista de portas que deseja expor e uma estratégia de espera. Essa parte da estratégia de espera é muito importante e voltaremos a ela mais tarde.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
público classe Teste de exemplo { @Regra de classe público estático Contêiner genérico couchbase = novo Contêiner genérico("mycouchbase:latest") .comExposedPorts(8091, 8092, 8093, 8094, 11207, 11210, 11211, 18091, 18092, 18093) .waitingFor(novo Estratégia de espera do Couchbase()); @Teste público vazio beerBucketTest() lançamentos InterruptedException { CouchbaseEnvironment env = DefaultCouchbaseEnvironment.construtor() .bootstrapCarrierDirectPort(couchbase.getMappedPort(11210)) .bootstrapCarrierSslPort(couchbase.getMappedPort(11207)) .bootstrapHttpDirectPort(couchbase.getMappedPort(8091)) .bootstrapHttpSslPort(couchbase.getMappedPort(18091)) .queryPort(couchbase.getMappedPort(8093)) .construir(); CouchbaseCluster cc = CouchbaseCluster.criar(env); Gerenciador de cluster cm = cc.gerenciador de cluster("Administrador", "senha"); assertTrue(cm.hasBucket("amostra de cerveja")); Balde balde = cc.openBucket("amostra de cerveja"); assertTrue(balde.existe("21st_amendment_brewery_cafe")); balde.próximo(); } |
Em seguida, você tem o método de teste. Começo definindo um novo CouchbaseEnvironment. Como todas as portas expostas foram mapeadas para uma porta diferente, precisamos especificá-las. Você pode obter a porta mapeada simplesmente chamando getMappedPort(yourPort) no GenericContainer. Em seguida, basta criar meu CouchbaseCluster e continuar com meu teste.
Isso só funciona porque adicionei uma estratégia de espera personalizada chamando waitingFor(new CouchbaseWaitStrategy())
. Por padrão, os TestContainers permitem que você espere que uma porta esteja acessível ou que uma chamada para um URL retorne um determinado código de status. Infelizmente, isso não é suficiente para o Couchbase. Quando você inicia um servidor Couchbase, há uma fase de aquecimento para os nós do seu cluster. Um GET em http://couchabseserver:8091/ui/index.html
retornaria um código de status 200 ou a porta 8091 responderia enquanto seu nó ainda estaria em fase de aquecimento, portanto, inacessível pelo SDK.
Isso significa que precisamos de uma estratégia de espera específica para saber se o status do nó está íntegro. Para saber se um nó está íntegro, você pode OBTER o seguinte URL http://couchabseserver:8091/pools/default/
. Ele retorna um JSON com informações sobre os nós de seu cluster. Isso significa que precisamos de uma estratégia de espera que obtenha esse JSON e teste se o status do nó é "saudável". É como usar um HTTPWaitStrategy com algum comportamento adicional.
Infelizmente, essa classe é composta principalmente de campos privados e protegidos, o que dificulta a extensão em meu projeto. Infelizmente, tive que duplicá-la e adicionar minha própria lógica. Você pode encontrar o código completo da estratégia de espera em Github. Esta é a parte que eu adicionei.
1 2 3 4 5 6 7 8 |
// Estratégia específica de espera do Couchbase para garantir que o nó esteja on-line e saudável JsonNode nó = om.readTree(conexão.getInputStream()); JsonNode statusNode = nó.em("/nodes/0/status"); Cordas status = statusNode.asText(); se (!"saudável".iguais(status)){ lançar novo Exceção de tempo de execução(Cordas.formato("O status do nó do Couchbase era: %s", status)); } |
Conclusão
Esse código ainda é bastante específico e exige que você crie sua própria imagem do Couchbase, já instalada e contendo dados. Ter imagens pré-fabricadas com dados prontos para testes de integração pode ser muito útil, especialmente para testes de integração. No entanto, talvez você queira ter uma abordagem mais leve para os testes de unidade. O TestContainers já tem vários módulos específicos para determinados bancos de dados. Tentaremos criar um para o Couchbase que não exija uma imagem específica e permita que você configure nossa imagem padrão da maneira que desejar para seus testes.
Informe-nos se desejar esses recursos!