DEV Community

Marlo Henrique
Marlo Henrique

Posted on

Leitura de arquivos CSV com k6

Na realização de testes de performance e outros tipos de testes funcionais e não funcionais, a parametrização de informações de forma dinâmica é frequentemente utilizada. Entre os tipos de arquivos mais comuns, podemos citar CSV e JSON.

Neste artigo, veremos como podemos manipular dados de arquivos CSV de forma eficiente com K6 utilizando o módulo experimental k6/experimental/csv.

Pré-requisitos📑

  • K6 instalado

Conhecendo o módulo CSV👩‍💻

O módulo CSV foi introduzido ao K6 na versão 0.54, estando atualmente no ciclo de vida experimental, onde a comunidade pode sugerir melhorias e sugestões via issue no GitHub do K6.

Foi construído pensando em oferecer aos usuários uma solução com equilíbrio entre desempenho e utilização de memória, oferecendo a possibilidade de analisar arquivos completos ou em fluxo via streaming, utilizando as seguintes operações:

  • csv.parse(): função que analisa um arquivo CSV completo utilizando uma estrutura de SharedArray distribuída entre todas as VUs por meio do processamento baseado em Go.
  • csv.Parser: classe utilizada como um fluxo de streaming que lê os arquivos CSV linha por linha, otimizando o uso de memória.

Configurações disponíveis para utilização📋

Tanto o csv.parse() quanto a classe csv.Parser permitem informar um objeto de options via construtor no momento de utilização, onde podemos descrever algumas configurações que queremos utilizar na manipulação do arquivo CSV.

Entre as principais propriedades que podemos definir nesse objeto, temos:

  • delimiter: caractere delimitador no seu CSV, onde o padrão é ,
  • asObjects: true se deseja que seu arquivo seja analisado como um objeto JavaScript. Caso false, os dados serão analisados como matrizes
  • skipFirstLine: se a primeira linha do CSV deve ser ignorada
  • fromLine: a partir de qual linha gostaria de iniciar a leitura do CSV
  • toLine: em qual linha a leitura do CSV deve ser interrompida

Ponto de atenção⚠️

Caso você defina a configuração asObjects como true e adicione a configuração skipFirstLine também como true, receberá uma saída com o seguinte erro:

ERRO[0000] failed to create a new parser; reason: the 'header' option cannot be enabled when 'skipFirstLine' is true  hint="script exception"
Enter fullscreen mode Exit fullscreen mode

Isso ocorre porque os cabeçalhos do CSV são necessários para o mapeamento correto do objeto.

Lendo um arquivo CSV📄

Para este tutorial, utilizaremos o seguinte arquivo CSV:

email, senha
0.09343697636021378@mail.com,user123
0.9820042509287148@mail.com,user123
0.8563382158459437@mail.com,user123
0.8227514039300216@mail.com,user123
0.9817821397952566@mail.com,user123
0.914560286115773@mail.com,user123
0.6211272282511351@mail.com,user123
Enter fullscreen mode Exit fullscreen mode

Inicialmente, na fase de inicialização, precisamos definir dois módulos que são essenciais: k6/experimental/fs e k6/experimental/csv:

import { open } from 'k6/experimental/fs';
import csv from 'k6/experimental/csv';
import { scenario } from 'k6/execution';
Enter fullscreen mode Exit fullscreen mode

Em alguns tutoriais, pode ser observada a utilização da função open do JavaScript. A utilização da função open do módulo experimental fs nos dá todos os benefícios de um módulo nativo.

Analisando um arquivo completo🔍

Podemos utilizar a função open para criar uma constante para nosso arquivo CSV:

const file = await open('usuarios.csv');
Enter fullscreen mode Exit fullscreen mode

E por meio da função parser(), carregar nossos dados como uma matriz em um sharedArray, informando o arquivo aberto anteriomente, e o objeto de options com as configurações de leitura do CSV:

const usuariosCsv = new csv.parser(file, { delimiter: ',', skipFirstLine: true });
Enter fullscreen mode Exit fullscreen mode

Nesse exemplo, estamos definindo as configurações de delimitação das linhas e ignorarando a primeira linha do arquivo.

E para acessa o conteudo do CSV podemos simplismente acessar:

export default async function () {
  console.log(usuariosCsv[scenario.iterationInTest]);
}
Enter fullscreen mode Exit fullscreen mode

Estamos utilizando as iterações do K6 como um índice para acessar as linhas do nosso CSV. Como todo o arquivo é carregado como uma matriz em um SharedArray, podemos acessar os valores individualmente com os índices das linhas e colunas, exemplo: usuariosCsv[indiceLinha][indiceColuna].

Caso seja utilizada a propriedade asObjects: true, o acesso às informações da linha pode ser simplesmente feito como um objeto chave-valor::

const usuariosCsv = new csv.parser(file, { delimiter: ',', asObjects: true });

export default async function () {
  console.log(usuariosCsv[scenario.iterationInTest].email);
}
Enter fullscreen mode Exit fullscreen mode

Analisando um arquivo como um fluxo🌀

Semelhante ao passo anterior, vamos utilizar a função open para criar uma constante para nosso arquivo CSV:

const file = await open('usuarios.csv');
Enter fullscreen mode Exit fullscreen mode

E por meio da classe Parser(), carregar as informações do nosso CSV como um fluxo de dados:

const usuariosCsv = new csv.Parser(file, { skipFirstLine: true });
Enter fullscreen mode Exit fullscreen mode

E para acessa o conteudo do CSV, podemos utilizar:

  const { done, value } = await usuariosCsv.next();

  console.log(`usuario: ${value[0]}, senha: ${value[1]}`);
Enter fullscreen mode Exit fullscreen mode

usuariosCsv.next() retorna um objeto com duas propriedades: a primeira, um valor booleano que indica se o fim do arquivo CSV foi alcançado; e a segunda, os dados em si da linha do arquivo.

Como estamos falando de um fluxo, temos otimização de recursos. No entanto, devemos nos preocupar com tratativas de acesso a linhas inexistentes.

Assim como no exemplo anterior, também podemos considerar o fluxo de leitura de dados como um objeto com a propriedade asObjects: true, onde nosso código será algo como:

const file = await open('usuarios.csv');
const usuariosCsv = new csv.Parser(file, { asObjects: true });

export default async function () {

   const { done, value } = await usuariosCsv.next();

   console.log(`usuario: ${value.usuario}, senha: ${value.senha}`);
}
Enter fullscreen mode Exit fullscreen mode

Conclusão❤️

O K6 tem passado por um processo de modernização, priorizando módulos nativos e otimizados. Os módulos CSV e fs são um retrato desse momento.
Quanto às estratégias de leitura, arquivo completo ou fluxo, podemos tirar dois aprendizados importantes:

  • Leitura completa com csv.parse(): pode levar ao aumento do uso de memória e do tempo de inicialização quando lida com arquivos muito grandes. No entanto, é extremamente eficiente em leitura e acesso distribuído entre VUs utilizando SharedArray.
  • Leitura em fluxo com csv.Parser: lê o arquivo linha por linha, mantendo o uso de memória baixo e evitando carregar todo o CSV na memória, mantendo um maior controle do usuário sobre o processamento das informações. No entanto, o usuário deve estar atento à sua responsabilidade de implementação de controle de fluxo ao atingir o fim do arquivo.

Gostou do conteúdo e quer saber mais sobre testes de performance com K6? Confira meu curso na Udemy!

Top comments (0)