---
title: "Documentação e Casos de Teste: Ferramentas Poderosas para Resolver Problemas de Desenvolvimento no OpenResty - API7.ai"
description: "O OpenResty não apenas fornece uma documentação detalhada com parâmetros de API, tipagem de valores de retorno e códigos de exemplo, mas também é testado minuciosamente com casos de teste, o que é útil para ajudar os desenvolvedores a utilizar o OpenResty."
url: "https://api7.ai/pt/learning-center/openresty/openresty-documentation-and-test-cases"
---

# Documentação e Casos de Teste: Ferramentas Poderosas para Resolver Problemas de Desenvolvimento no OpenResty

API7.ai

October 23, 2022

[OpenResty (NGINX + Lua)](https://api7.ai/learning-center/openresty)

Após aprender os princípios e alguns conceitos essenciais do OpenResty, finalmente vamos começar a aprender a API.

Pela minha experiência pessoal, aprender a API do OpenResty é relativamente fácil, então não são necessários muitos artigos para apresentá-la. Você pode se perguntar: a API não é a parte mais comum e essencial? Por que não gastar muito tempo nela? Há duas considerações principais.

Primeiro, o OpenResty fornece uma documentação muito detalhada. Comparado com muitas outras linguagens de programação ou plataformas, o OpenResty não apenas fornece os parâmetros da API e as definições de valores de retorno, mas também exemplos de código completos e executáveis, mostrando claramente como a API lida com várias condições de contorno.

Seguir a definição da API com exemplos de código e advertências é um estilo consistente da documentação do OpenResty. Portanto, após ler a descrição da API, você pode imediatamente executar o código de exemplo em seu ambiente e modificar os parâmetros e a documentação para verificá-los e aprofundar seu entendimento.

Segundo, o OpenResty fornece casos de teste abrangentes. Como mencionei, a documentação do OpenResty mostra exemplos de código das APIs. No entanto, devido a limitações de espaço, o documento não apresenta relatórios de erros e processamento em várias situações anormais e o método de uso de múltiplas APIs.

Mas não se preocupe. Você pode encontrar a maioria desses conteúdos no conjunto de casos de teste.

Para desenvolvedores do OpenResty, os melhores materiais de aprendizado da API são a documentação oficial e os casos de teste, que são profissionais e amigáveis para os leitores.

Dê um peixe a um homem, e você o alimentará por um dia; ensine um homem a pescar, e você o alimentará por toda a vida. Vamos usar um exemplo real para experimentar como exercer o poder da documentação e do conjunto de casos de teste no desenvolvimento do OpenResty.

## Tomemos a API `get` do shdict como exemplo

Baseado na área de memória compartilhada do NGINX, o dicionário compartilhado (shared dict) é um objeto de dicionário Lua, que pode acessar dados entre vários workers e armazenar dados como limitação de taxa, cache, etc. Há mais de 20 APIs relacionadas ao dicionário compartilhado - a API mais comumente usada e crucial no OpenResty.

Vamos tomar a operação mais simples, `get`, como exemplo; você pode clicar no [link da documentação](https://github.com/openresty/lua-nginx-module/#ngxshareddictget) para comparação. O seguinte exemplo de código minimizado é adaptado da documentação oficial.

```
http {
      lua_shared_dict dogs 10m;
      server {
          location /demo {
              content_by_lua_block {
                  local dogs = ngx.shared.dogs
                  dogs:set("Jim", 8)
                  local v = dogs:get("Jim")
                  ngx.say(v)
              }
          }
      }
  }
```

Como uma nota rápida, antes de podermos usar o dicionário compartilhado no código Lua, precisamos adicionar um bloco de memória no `nginx.conf` com a diretiva `lua_shared_dict`, que é nomeado "dogs" e tem um tamanho de 10M. Após modificar o `nginx.conf`, você precisa reiniciar o processo e acessá-lo com um navegador ou comando `curl` para ver os resultados.

Isso não parece um pouco tedioso? Vamos modificá-lo de forma mais direta. Como você pode ver, usar o CLI resty dessa forma tem o mesmo efeito que incorporar o código no `nginx.conf`.

```
$ resty --shdict 'dogs 10m' -e 'local dogs = ngx.shared.dogs
 dogs:set("Jim", 8)
 local v = dogs:get("Jim")
 ngx.say(v)
 '
```

Agora você sabe como o `nginx.conf` e o código Lua funcionam juntos, e você executou com sucesso os métodos set e get do dicionário compartilhado. Geralmente, a maioria dos desenvolvedores para por aí. Há algumas coisas que valem a pena notar aqui.

1. Em quais fases não se pode usar as APIs relacionadas à memória compartilhada?
2. Vemos no código de exemplo que a função get tem apenas um valor de retorno. Então, quando haverá mais de um valor de retorno?
3. Qual é o tipo de entrada da função get? Há um limite de comprimento?

Não subestime essas perguntas; elas podem nos ajudar a entender melhor o OpenResty, e vou levá-lo através delas individualmente.

### Pergunta 1: Em quais fases não se pode usar as APIs relacionadas à memória compartilhada?

Vamos olhar para a primeira pergunta. A resposta é simples; a documentação tem uma seção `context` (ou seja, seção de contexto) dedicada que lista os ambientes nos quais a API pode ser usada.

```
context: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*
```

Como você pode ver, as fases `init` e `init_worker` não estão incluídas, o que significa que a API `get` da memória compartilhada não pode ser usada nessas duas fases. Por favor, note que cada API de memória compartilhada pode ser usada em diferentes fases. Por exemplo, a API `set` pode ser usada na fase `init`.

Sempre leia a documentação ao usá-la. Claro, a documentação do OpenResty às vezes contém erros e omissões, então você precisa verificá-los com testes reais.

A seguir, vamos modificar o conjunto de testes para garantir que a fase `init` possa executar a API `get` do dicionário compartilhado.

Como podemos encontrar o conjunto de casos de teste relacionados à memória compartilhada? Os casos de teste do OpenResty estão todos no diretório `/t` e nomeados regularmente, ou seja, `número-auto-incrementado-nome-da-função.t`. Pesquise por `shdict`, e você encontrará `043-shdict.t`, o conjunto de casos de teste da memória compartilhada, que contém cerca de 100 casos de teste, incluindo testes para várias circunstâncias normais e anormais.

Vamos tentar modificar o primeiro caso de teste.

Você pode substituir a fase `content` por uma fase `init` e remover o código supérfluo para ver se a interface `get` funciona. Você não precisa entender como o caso de teste é escrito, organizado e executado neste estágio. Você só precisa saber que ele está testando a interface `get`.

```
 === TEST 1: string key, int value
     --- http_config
         lua_shared_dict dogs 1m;
     --- config
         location = /test {
             init_by_lua '
                 local dogs = ngx.shared.dogs
                 local val = dogs:get("foo")
                 ngx.say(val)
             ';
         }
     --- request
     GET /test
     --- response_body
     32
     --- no_error_log
     [error]
     --- ONLY
```

Você deve ter notado que no final do caso de teste, adicionei a flag `--ONLY`, o que significa ignorar todos os outros casos de teste e executar apenas este, aumentando assim a velocidade de execução. Mais tarde, na seção de testes, explicarei especificamente as várias tags.

Após a modificação, podemos executar o caso de teste com o comando `prove`.

```
prove t/043-shdict.t
```

Então, você receberá um erro que corrobora os limites de fase descritos na documentação.

```
nginx: [emerg] "init_by_lua" directive is not allowed here
```

### Pergunta 2: Quando a função `get` tem múltiplos valores de retorno?

Vamos olhar para a segunda pergunta, que pode ser resumida a partir da documentação oficial. A documentação começa com a descrição `syntax` desta interface.

```
value, flags = ngx.shared.DICT:get(key)
```

Em circunstâncias normais.

- O primeiro parâmetro `value` retorna o valor correspondente à `key` no dicionário; no entanto, quando a `key` não existe ou expira, o valor `value` é `nil`.
- O segundo parâmetro, `flags`, é um pouco mais complicado; se a interface set definir flags, ele as retorna. Caso contrário, não.

Se a chamada da API der errado, `value` retorna `nil`, e `flags` retorna uma mensagem de erro específica.

A partir das informações resumidas na documentação, podemos ver que `local v = dogs:get("Jim")` é escrito com apenas um parâmetro de recebimento. Tal escrita é incompleta porque cobre apenas o cenário de uso típico sem receber um segundo parâmetro ou realizar tratamento de exceções. Poderíamos modificá-lo da seguinte forma.

```
local data, err = dogs:get("Jim")
if data == nil and err then
    ngx.say("get not ok: ", err)
    return
end
```

Como com a primeira pergunta, podemos pesquisar o conjunto de casos de teste para confirmar nosso entendimento da documentação.

```
  === TEST 65: get nil key
     --- http_config
         lua_shared_dict dogs 1m;
     --- config
         location = /test {
             content_by_lua '
                 local dogs = ngx.shared.dogs
                 local ok, err = dogs:get(nil)
                 if not ok then
                     ngx.say("not ok: ", err)
                     return
                 end
                 ngx.say("ok")
             ';
         }
     --- request
     GET /test
     --- response_body
     not ok: nil key
     --- no_error_log
     [error]
```

Neste caso de teste, a interface `get` tem uma entrada `nil`, e a mensagem de erro retornada é `nil key`. Isso verifica que nossa análise da documentação está correta e fornece uma resposta parcial à terceira pergunta. Pelo menos, a entrada para get não pode ser nil.

### Pergunta 3: Qual é o tipo de entrada da função `get`?

Quanto à terceira pergunta, que tipo de parâmetros de entrada para `get` ele pode ser? Vamos verificar a documentação primeiro, mas infelizmente, você descobrirá que a documentação não especifica quais são os tipos legais de chaves. O que devemos fazer?

Não se preocupe. Pelo menos sabemos que a `key` pode ser do tipo string e não pode ser nil. Você se lembra dos tipos de dados em Lua? Além de strings e nil, há números, arrays, tipos booleanos e funções. Os dois últimos são desnecessários como chaves, então só precisamos verificar os dois primeiros: números e arrays. Podemos começar pesquisando no arquivo de teste por casos em que números são usados como `key`.

```
=== TEST 4: number keys, string values
```

Com este caso de teste, você pode ver que números também podem ser usados como chaves, e internamente eles serão convertidos em strings. E arrays? Infelizmente, o caso de teste não cobre isso, então precisamos tentar nós mesmos.

```
$ resty --shdict 'dogs 10m' -e 'local dogs = ngx.shared.dogs
 dogs:get({})
 '
```

Sem surpresa, o seguinte erro foi relatado.

```
ERROR: (command line -e):2: bad argument #1 to 'get' (string expected, got table)
```

Em resumo, podemos concluir que os tipos de `key` aceitos pela API `get` são strings e números.

Então, há um limite de comprimento para a chave de entrada? Há um caso de teste correspondente aqui.

```
=== TEST 67: get a too-long key
     --- http_config
         lua_shared_dict dogs 1m;
     --- config
         location = /test {
             content_by_lua '
                 local dogs = ngx.shared.dogs
                 local ok, err = dogs:get(string.rep("a", 65536))
                 if not ok then
                     ngx.say("not ok: ", err)
                     return
                 end
                 ngx.say("ok")
             ';
         }
     --- request
     GET /test
     --- response_body
     not ok: key too long
     --- no_error_log
     [error]
```

Quando o comprimento da string é 65536, você será informado de que a chave é muito longa. Você pode tentar mudar o comprimento para 65535, embora apenas 1 byte a menos, mas não haverá mais erros. Isso significa que o comprimento máximo da chave é exatamente 65535.

## Resumo

Finalmente, gostaria de lembrá-lo de que, na API do OpenResty, qualquer valor de retorno com uma mensagem de erro deve ter uma variável para recebê-lo e fazer o tratamento de erros, caso contrário, cometerá um erro. Por exemplo, se a conexão errada for colocada no pool de conexões, ou se a chamada da API falhar e continuar a lógica por trás dela, isso fará as pessoas reclamarem incessantemente.

Então, se você encontrar um problema ao escrever código OpenResty, qual é a sua maneira usual de resolvê-lo? É documentação, listas de discussão ou outros canais?

Sinta-se à vontade para compartilhar este artigo com seus colegas e amigos para que possamos nos comunicar e melhorar.

Share article link

Share

Related Posts

[![FAQ do OpenResty | Como o OpenResty é usado na prática](https://static.api7.ai/uploads/2023/02/12/jbv9M0zi_Hello%20World%20in%20OpenResty%20%283%29.png)](https://api7.ai/learning-center/openresty/faq-5)

## [FAQ do OpenResty | Como o OpenResty é usado na prática](https://api7.ai/learning-center/openresty/faq-5)

[![Parte 3: Como Construir um API Gateway de Microservices Usando OpenResty](https://static.api7.ai/uploads/2023/02/07/3XJXY9Jy_45.png)](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

## [Parte 3: Como Construir um API Gateway de Microservices Usando OpenResty](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

Table of Contents

- [Tomemos a API `get` do shdict como exemplo](#tomemos-a-api-get-do-shdict-como-exemplo)

  - [Pergunta 1: Em quais fases não se pode usar as APIs relacionadas à memória compartilhada?](#pergunta-1-em-quais-fases-n%C3%A3o-se-pode-usar-as-apis-relacionadas-%C3%A0-mem%C3%B3ria-compartilhada)
  - [Pergunta 2: Quando a função `get` tem múltiplos valores de retorno?](#pergunta-2-quando-a-fun%C3%A7%C3%A3o-get-tem-m%C3%BAltiplos-valores-de-retorno)
  - [Pergunta 3: Qual é o tipo de entrada da função `get`?](#pergunta-3-qual-%C3%A9-o-tipo-de-entrada-da-fun%C3%A7%C3%A3o-get)

- [Resumo](#resumo)
