Em um sistema que estava desenvolvendo me deparei com a seguinte demanda, ler um arquivo csv e devolver seu primeiro resultado para analise, um arquivo csv podem vir com a primeira linha sendo um cabeçalho, logo essa linha deve ser ignorada e a segunda linha deve ser retornada ao invés da primeira.
O codigo para essa tarefa é simples.
public function getFirstContent(string $filename, UploadedFile $file, bool $hasHeader = false): array
{
$openFile = $file->openFile();
$csv = [];
while (($row = $openFile->fgets()) !== false) {
if ($hasHeader) {
continue;
}
$csv = str_getcsv($row);
break;
}
$openFile = null;
$file->storeAs(self::SAVE_DIR, $filename);
return $csv;
}
Você pode ter notado o erro desta implementação, eu não. Após terminar de fazer esse código fui fazer os testes desta função. Escrevi testes com um caso onde o csv não teria um cabeçalho e o outro teria um cabeçalho, um teste deveria chamar a função fgets
uma vez e outro duas, eis o codigo do teste
/**
* @dataProvider cases
*/
public function testGetFistContent(bool $hasHeader, array $fgets, string $expected): void
{
// arrange
$splFileMock = $this->getMockBuilder(SplFileObject::class)
->setConstructorArgs(['php://memory'])
->getMock();
$splFileMock->expects($this->exactly(count($fgets)))->method('fgets')->willReturnOnConsecutiveCalls(...$fgets);
$file = $this->createMock(UploadedFile::class);
$file->expects($this->once())->method('openFile')->willReturn($splFileMock);
$file->expects($this->once())->method('storeAs')->with('/tmp', 'file.csv');
// act
$result = $this->service->getFirstContent('file.csv', $file, $hasHeader);
// assert
$this->assertIsArray($result);
$this->assertSame($expected, $result[0]);
}
public function cases(): array
{
return [
[false, ['a,b,c'], 'a'],
[true, ['a,b,c', 'c,b,a'], 'c']
];
}
O primeiro teste rodou de forma correta e passou, o segundo caso, onde o cabeçalho existe e deve ser pulada não estava passando, justamente porque $hasHeader
nunca muda seu estado, logo quando for true
, sempre irá pular a linha e nunca lerá o csv, um erro simples, fácil de ser corrigido, porém com um alto potencial de quebrar sistemas, imagine o quando de processamento desnecessário um loop infinito irá gerar?
Ao notar isso adicionei a uma linha de correção, um simples $hasHeader = false
e pronto, o teste passou.
while (($row = $openFile->fgets()) !== false) {
if ($hasHeader) {
$hasHeader = false;
continue;
}
$csv = str_getcsv($row);
break;
}
Testes são importantes para prevenir erros de falta de atenção, que podem ocorrer quando estamos com um prazo apertado ou no dia em que não estamos muito inspirados.
Sempre teste seu código, até mais!
Top comments (0)