Automatizando testes de códigos de barras 1D (boletos bancários)

zebra
Recentemente nos projetos em que atuo, tive a necessidade de automatizar um cenário de validação de código de barras de um boleto bancário. Neste post, desejo compartilhar a solução utilizada, o que aprendi e como você pode aplicar isto em seus projetos.

Curiosidades:

Antes de começar, deixe-me te passar algumas informações sobre códigos de barras, que serão úteis posteriormente no processo de automatização:

  • Existem três formatos: 1D (mais comum, produtos por exemplo), 2D(QR_code) e 3D(pouco utilizado, mas por existem algumas propostas conceituais, como o QR Code colorido, sem a cor a 3ª dimensão)
  • Para os códigos de barras 1D, podemos dividir em 1D com padrões de produtos e 1D com padrões industriais- Existem diversos padrões de códigos de barras diferentes para cada uma das dimensões
  • O padrão utilizado pelo boleto bancário aqui no Brasil (grande parte) é o ITF – Intervealed Two of Five
  • No caso do boleto: o valor interpretado pelo código de barras não é o mesmo da linha digitável. Ambos possuem as mesmas informações, mas distribuídas em uma ordem diferente.

Vamos falar sobre a API Zxing

A Zebra Crossing API (Zxing) é uma API para geração e decodificação de códigos de barras 1D/2D. Possui implementação em Java e em outras linguagens como .NET, Javascript, Ruby dentre outras. No meu caso, realizei as implementações utilizando Java.
Abaixo, outras informações úteis sobre a API:

  • Serve para gerar e interpretar códigos de barras de 1D e 2D
  • Aceita diversos modelos (Barcode, QR Code) e diversos padrões
  • Possui o funcionamento semelhante a API/IO do Java- Encontra o código de barras dentro da imagem. Na maioria dos casos, não é necessário uma imagem somente com o código de barras.
  • Possui implementação e wrappers para outras linguagens- Sugestão de validação: ZXing Decoder Online

Validei a consistência de códigos de barras na página web e documento PDF. Abaixo, deixo um passo a passo e alguns exemplos para implementação:
Passo a passo:
1. O primeiro passo é pegar uma imagem do código de barras desejado. Se houver apenas um códigos de barras na tela, a imagem pode ser da tela inteira desde que o código de barras apareça.
2. Utilizando a imagem que salvamos, agora vamos pegar o valor “por extenso”, interpretado, do código de barras.
3. O valor do código de barras precisa ser “transformado” em linha digitável. Logo, vamos fazer isto: transformar o valor do código de barras no padrão de linha digitável.
4. Pegue o valor da linha digitável que será comparada.
5. Com os dois textos “em mãos”, remova os espaçamentos antes, depois e entre os caracteres, assim garantimos que ambos estarão exatamente iguais em tamanho.
6. Compare os dois textos.
7. Shazam! Confira se o resultado está de acordo com o esperado.

Para os passos acima, utilizei duas bibliotecas auxiliares. Preferi descrever em passos os itens acima para que tenhas liberdade para utilizar outras bibliotecas que conheça e que atendam as mesmas necessidades.

Selenium

  • Mapear os elementos
  • Pegar imagem da tela
  • Cortar imagem para pegar apenas o “pedaço” com o código de barras

PDFBox

  • Pegar o conteúdo de um PDF em formato de imagem
  • Pegar o conteúdo do PDF em formato de String

Stella Core

  • Gerar linha digitável a partir do código de barras

Chega de teoria. Vamos aos exemplos! (Java):

1. Pegando imagem

File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage imagem = ImageIO.read(screenshot);</pre>

Se você prefere uma imagem só do trecho onde o código de barras aparece, pode realizar um corte na imagem, da seguinte forma:

//Pegando a posicao do elemento
Point posicao = codigoDeBarras.getLocation();</pre>
//Pegando altura e largura do elemento

int larguraElemento = codigoDeBarras.getSize().getWidth();int alturaElemento = codigoDeBarras.getSize().getHeight();

//Recortando a imagem

BufferedImage imagemCortada = imagem.getSubImage(point.getX(), point.getY(), eleWidth, eleHeight);
ImageIO.write(imagemCortada, "jpg", imagem);

2. Pegando o valor por extenso, interpretado do código de barras


InputStream codDeBarrasInpStream = new FileInputStream(imagemCortada); 
BufferedImage codDeBarrasBuffImage = ImageIO.read(codDeBarrasInpStream);

//Passa a imagem para uma escala de cinza. Servirá para auxiliar nos passos seguintes. 
LuminanceSource source = new BufferedImageLuminanceSource(codDeBarrasBuffImage);

//O Reader do Zxing identifica e interpreta sequências binárias que estejam de acordo com determinados padrões(ITF, EAN, QR Code, etc)

//O HybridBinarizer serve para passar uma imagem em determinada escalar para uma sequência binária.

//O BynaryBitMap passa a sequência binária para uma sequência compreensível para o Reader. Isso posibilita a decodificação da sequência binária.

BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

//Leitor do código binário gerado anteriormente. É praticamente o passo final para a decodificação!

Reader reader = new MultiFormatReader(); Result result = reader.decode(bitmap); System.out.println("Código de barras interpretado: "+result.getText());

//Se quiser fazer uma validação específica, o result possui um método 
//que retorna qual o formato identificado após a decodificação:

System.out.println("Formato do código de barras: "+result.getFormat());

3. Transformando o valor interpretado em uma linha digitável.


//Utilizei a biblioteca Stella Core da Caelum que já possui um Gerador de linha digitável implementado.

GeradorDeLinhaDigitavel geraLinhaDigitavel = new GeradorDeLinhaDigitavel();

//Passe o banco de acordo com desejado. Neste exemplo, estou usando o Banco do Brasil

String linhaDigitavelGerada = geraLinhaDigitavel.geraLinhaDigitavelPara(codigoDeBarras, Bancos.BANCO_DO_BRASIL.getBanco()); System.out.println("Linha digitável gerada: "+linhaDigitavelGerada);

4. Pegando o valor da linha digitável


//Vou utilizar um exemplo, mas o principal é: encontrar o elemento na tela e pegar seu conteúdo

WebElement elemento = driver.findElement(By.id("linhaDigitavelExemplo"));

String stringLinhaDigitavelTela = elemento.getText(); //ou elemento.getAttribute("value");

System.out.println("Linha digitável na tela: "+stringLinhaDigitavelTela);

5. Removendo espaçamentos para garantir que estejam na mesma formatação


//Neste caso, removi espaços em branco e tabulações.

String linhaDigitavelGerada = linhaDigitavelGerada.replaceAll(" ", "");

stringLinhaDigitavelTela = stringLinhaDigitavelTela.replaceAll(" ", "").replaceAll("\t", "");

6. Comparando os dois textos


boolean estaoIguais = linhaDigitavelGerada.equals("stringLinhaDigitavelTela"); System.out.println("Estão iguais? "+estaoIguais);

7. Conferindo o resultado


//A comparação já nos diz se está OK ou não mas, vale a pena conferir
//Aqui você pode utilizar esses dois resultados em um Assert, por exemplo.

System.out.println("Linha digitavel gerada: "+linhaDigitavelGerada); System.out.println("Linha digitavel boleto: "+stringLinhaDigitavelTela);

Para PDF o processo é praticamente o mesmo. A única coisa que fiz diferente foi a forma como pego a linha digitável: Com a API PDFBox eu passei todo o conteúdo do PDF para String. A partir daí, recortei o trecho onde exibe a linha digitável e utilizei na comparação.


//Passando o caminho do arquivo.

String caminhoArquivo = "/src/test/resources/exemplo/";

File arquivo = new File(caminhoArquivo);

//Realizando a leitura do arquivo

PDF. PDDocument documento = PDDocument.load(pdfFilePath);

//Interpreta o conteúdo do PDF para o formato de texto

String stringPdf = new PDFTextStripper().getText(documento);
//Recortando o trecho onde a linha digitável é exibida

String linhaDigitavelPdf = stringPdf.substring(inicioLinhaDigitavel, fimLinhaDigitavel);

Utilizei também a PDFBox para pegar o conteúdo do PDF como imagem. Com isso, pego a imagem do código de barras no PDF.


//Passando o caminho do arquivo.

String caminhoArquivo = "/src/test/resources/exemplo/";

File arquivo = new File(caminhoArquivo);

//Realizando leitura do arquivo PDF.

PDDocument documento = PDDocument.load(arquivo);

//Instanciando a classe que renderiza o PDF

PDFRenderer renderizador = new PDFRenderer(documento);

//Renderizando uma imagem de um documento PDF. Tira print sempre da última página.

BufferedImage image = renderizador.renderImage(document.getNumberOfPages()-1);

//Escrevendo a imagem em um arquivo

ImageIO.write(image, "JPEG", new File(System.getProperty("user.dir") + "/src/test/resources/exemplo/img/imagem_exemplo.jpg")); 

//fechando o documento após o uso document.close();
document.close()

—-

Espero que com o passo a passo e exemplos você consiga realizar a implementação em seus projetos assim que houver necessidade. Já utilizou este tipo de validação de alguma outra forma? Compartilhe aí! 🙂

Links úteis:

… ps.: Em breve farei uma v2 baseada neste post, explicando como utilizar o Cucumber, seguindo este mesmo projeto como base e exemplo.

… ps².: Vou disponibilizar o projeto de exemplo em algum repositório, mas que você possa utilizar em seus estudos.

… ps³.: Se você chegou até aqui, muito obrigado. Aproveita e deixa teu comentário, se serviu, se já usou algo parecido, se não gostou, fique a vontade e mais uma vez, obrigado!

Anúncios

3 comentários sobre “Automatizando testes de códigos de barras 1D (boletos bancários)

  1. Ótimo tutorial amigo, estou implementando um validador de códigos de barra e estou seguindo seus passos, porém quando eu instancio o objeto da classe BufferedImageLuminanceSource, retorna “cannot be resolved as a type”. Gostaria de saber se ja aconteceu contigo algo similar. Obrigado desde já.

    Curtido por 1 pessoa

    • Olá Kevin! Que legal! Compartilha depois como foi a tua experiência 🙂

      Sobre a sua dúvida, você está tentando criar o objeto da seguinte forma?

      LuminanceSource source = new BufferedImageLuminanceSource(codDeBarrasBuffImage);

      Acho válido verificar se a importação / inclusão da biblioteca no build path funcionaram corretamente.

      A classe LuminanceSource é parte da API zxing, e se estiver com a biblioteca importada, deve funcionar. Recomendo dar uma conferida na documentação desta classe também: https://zxing.github.io/zxing/apidocs/com/google/zxing/LuminanceSource.html

      Acredito que seja isso, espero que ajude! Depois me avisa se deu certo 😉

      Abração

      Curtir

      • Outra dúvida na hora de Inicializar as variaveis inicioLinhaDigitavel e fimLinhaDigitavel, qual o valor que devo iniciar elas. Quando rodo o codigo, caio nessa exception : Gostaria de saber se esse erro pode ser na hora de inicializar as var da linha digitavel. Quando terminar de implementar eu mostro como ficou.
        Exception in thread “main” java.lang.IllegalArgumentException: O código de barras precisa ter 44 digitos
        at br.com.caelum.stella.boleto.bancos.GeradorDeLinhaDigitavel.geraLinhaDigitavelPara(GeradorDeLinhaDigitavel.java:27)
        at ValidadorPDF.ProjetoPDF.Validador.validadorPdf(Validador.java:35)
        at ValidadorPDF.ProjetoPDF.Validador.main(Validador.java:51)

        Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s