Verifique uma função de agregação com quatro linhas que você pode calcular manualmente e 12 unit tests. Verifique não apenas valores normais, mas também entrada vazia, zero, decimais e entrada inválida.
Conteúdo verificado 2026.09.19Inclui arquivos de exemplo
Ver o sumário
A tradução foi feita com IA. Confira o código, as unidades e os valores junto com o original. A revisão por falantes nativos de cada idioma ainda não foi concluída. English
Para quem éIniciantes que hesitam em usar código Python gerado por IA no trabalho apenas porque ele executa
Preparação
Instale Python 3.12 ou posterior e verifique a versão em um terminal com python --version.
Extraia o ZIP de exemplo em uma nova pasta. Não execute o exemplo de dentro do arquivo ZIP.
Abra um terminal na pasta que contém example.py. Se o comando python não estiver disponível no Windows, use py. No macOS ou Linux, use python3 se seu ambiente exigir.
Nenhum pacote externo ou conta é necessário. Os arquivos incluídos são dados sintéticos criados para este tutorial.
01Decida a resposta antes de executar
O código de uma IA terminar sem erros não significa que o cálculo esteja correto. Este artigo não se conecta a um serviço real de IA; ele pratica as etapas de verificação com uma função de agregação escrita de forma independente e pequenos dados sintéticos. Você pode aplicar o mesmo método a uma função que precise revisar. Nenhuma API key ou pacote externo é necessário.
Leia as quatro linhas de input.csv e calcule quantity × unit price por conta própria.
Abra expected.json e verifique se ele lista 4 rows, quantity 6 e amount 11101.50.
Execute o comando abaixo. Os 12 unit tests são executados primeiro, seguidos pela CSV aggregation e comparação com os expected values.
Verifique outputs/summary.json e verification.txt, que são criados somente quando todas as comparações passam.
bash
python example.py
02Compare o cálculo de quatro linhas em uma tabela
item
quantity
unit_price
Valor por linha
노트
2
2500.00
5000.00
펜
3
1200.50
3601.50
노트
1
2500.00
2500.00
Sample
0
999.99
0.00
Há 4 rows, mas a total quantity é 2 + 3 + 1 + 0 = 6. O total amount é 5000.00 + 3601.50 + 2500.00 = 11101.50. A última linha, com quantity 0, ainda é contada no número de input rows. Por item, 노트 (notebook) tem quantity 3 e amount 7500.00, 펜 (pen) tem quantity 3 e amount 3601.50, e 샘플 (sample) tem quantity 0 e amount 0.00.
Portanto, não compare apenas o total; observe juntos row count, total quantity e per-item values. Inserir o mesmo item em duas linhas, como notebook, também permite verificar grouping e summing. A ordem dos per-item results é classificada por name e não significa sales rank nem input order.
03Escreva as regras de entrada aceitas pela função
Item
Regra permitida
Exemplo rejeitado
Column
Três: item, quantity, unit_price
Columns ausentes ou extras
item
String não vazia após remover leading e trailing spaces
String vazia ou apenas whitespace
quantity
Integer string de 0 a 1,000,000
-1, 1.5, 1e2
unit_price
0 a 1,000,000,000, até duas casas decimais
NaN, Infinity, 0.001, 1,000
Assume-se que os amounts estão na mesma moeda fictícia. Negative quantities e unit prices não são permitidos, portanto não existe uma regra para representar returns. Definir primeiro as input rules permite saber se o código altera silenciosamente valores para 0 ou ignora algumas rows. Esta função para com ValueError quando encontra uma invalid row.
04Código completo com a agregação e os testes
aggregate_sales retorna apenas o result sem alterar as input rows. A leitura de arquivos e a gravação de resultados são separadas em main. Dessa forma, os tests podem passar small dictionaries diretamente e verificar apenas o cálculo. Cada expected value é comparado com assertEqual, e os values que devem ser rejeitados são verificados com assertRaises.
example.py
"""집계 함수를 손계산 기대값과 unittest로 검증합니다. 외부 AI 호출은 없습니다."""
import argparse
import csv
import json
import re
import sys
import unittest
from decimal import Decimal
from pathlib import Path
BASE = Path(__file__).resolve().parent
OUTPUT = BASE / "outputs"
FIELDS = {"item", "quantity", "unit_price"}
def money(cents):
return f"{cents // 100}.{cents % 100:02d}"
def aggregate_sales(rows):
"""문자열 딕셔너리 행을 검증하고 집계합니다. rows와 원본 파일을 변경하지 않습니다."""
totals = {}
row_count = total_quantity = total_cents = 0
for number, row in enumerate(rows, start=1):
if not isinstance(row, dict) or set(row) != FIELDS:
raise ValueError(f"{number}행: item,quantity,unit_price 세 열이 필요합니다.")
if any(not isinstance(value, str) for value in row.values()):
raise ValueError(f"{number}행: 모든 값은 문자열이어야 합니다.")
item, quantity_text, price_text = (row[key].strip() for key in ("item", "quantity", "unit_price"))
if not item:
raise ValueError(f"{number}행: 품목이 비어 있습니다.")
if not re.fullmatch(r"[0-9]{1,7}", quantity_text):
raise ValueError(f"{number}행: 수량은 0 이상의 정수여야 합니다.")
quantity = int(quantity_text)
if quantity > 1_000_000:
raise ValueError(f"{number}행: 수량은 1,000,000 이하여야 합니다.")
if not re.fullmatch(r"[0-9]{1,10}(?:\.[0-9]{1,2})?", price_text):
raise ValueError(f"{number}행: 단가는 0 이상, 소수점 둘째 자리까지 입력하세요.")
price = Decimal(price_text) # 문자열에서 직접 생성해 float 오차를 피합니다.
if price > Decimal("1000000000"):
raise ValueError(f"{number}행: 단가는 1,000,000,000 이하여야 합니다.")
cents = int(price * 100) * quantity
bucket = totals.setdefault(item, {"quantity": 0, "cents": 0})
bucket["quantity"] += quantity
bucket["cents"] += cents
total_quantity += quantity
total_cents += cents
row_count += 1
return {
"row_count": row_count,
"quantity": total_quantity,
"amount": money(total_cents),
"by_item": [
{"item": item, "quantity": totals[item]["quantity"], "amount": money(totals[item]["cents"])}
for item in sorted(totals)
],
}
def sale(item="펜", quantity="1", unit_price="1200.50"):
return {"item": item, "quantity": quantity, "unit_price": unit_price}
class TestAggregate(unittest.TestCase):
# 기대값은 검증 대상 함수로 만들지 않고 손계산한 상수로 적습니다.
def test_empty_input(self):
self.assertEqual(aggregate_sales([]), {"row_count": 0, "quantity": 0, "amount": "0.00", "by_item": []})
def test_single_row(self):
self.assertEqual(aggregate_sales([sale(quantity="3")])["amount"], "3601.50")
def test_zero_quantity(self):
result = aggregate_sales([sale(quantity="0")])
self.assertEqual((result["row_count"], result["quantity"], result["amount"]), (1, 0, "0.00"))
def test_repeated_item(self):
result = aggregate_sales([sale(quantity="2"), sale(quantity="1")])
self.assertEqual(result["by_item"], [{"item": "펜", "quantity": 3, "amount": "3601.50"}])
def test_decimal_addition(self):
result = aggregate_sales([sale(unit_price="0.10"), sale(unit_price="0.20")])
self.assertEqual(result["amount"], "0.30")
def test_whitespace(self):
result = aggregate_sales([sale(item=" 펜 ", quantity=" 1 ", unit_price=" 2.00 ")])
self.assertEqual(result["by_item"], [{"item": "펜", "quantity": 1, "amount": "2.00"}])
def test_bad_quantity(self):
for value in ("-1", "1.5", "", "1000001", "1e2", "1"):
with self.subTest(value=value), self.assertRaises(ValueError):
aggregate_sales([sale(quantity=value)])
def test_bad_price(self):
for value in ("-1", "0.001", "NaN", "Infinity", "", "1,000", "1000000001"):
with self.subTest(value=value), self.assertRaises(ValueError):
aggregate_sales([sale(unit_price=value)])
def test_blank_item(self):
with self.assertRaises(ValueError):
aggregate_sales([sale(item=" ")])
def test_wrong_columns(self):
for row in ({"item": "펜"}, {**sale(), "extra": "x"}):
with self.subTest(row=row), self.assertRaises(ValueError):
aggregate_sales([row])
def test_non_string(self):
with self.assertRaises(ValueError):
aggregate_sales([sale(quantity=True)])
def test_upper_boundary(self):
self.assertEqual(
aggregate_sales([sale(quantity="1000000", unit_price="1000000000")])["amount"],
"1000000000000000.00",
)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--test", action="store_true", help="단위 테스트만 실행합니다.")
args = parser.parse_args()
# unittest의 명시적 비교는 python -O에서도 생략되지 않습니다.
result = unittest.TextTestRunner(verbosity=2, stream=sys.stdout).run(
unittest.defaultTestLoader.loadTestsFromTestCase(TestAggregate)
)
if not result.wasSuccessful():
return 1
if args.test:
return 0
if OUTPUT.exists() or OUTPUT.is_symlink():
raise FileExistsError("outputs가 이미 있습니다. 기존 결과를 옮긴 뒤 실행하세요.")
with (BASE / "input.csv").open("r", encoding="utf-8-sig", newline="") as stream:
reader = csv.DictReader(stream, strict=True)
if reader.fieldnames != ["item", "quantity", "unit_price"]:
raise ValueError("input.csv의 열은 item,quantity,unit_price 순서여야 합니다.")
actual = aggregate_sales(reader)
expected = json.loads((BASE / "expected.json").read_text(encoding="utf-8"))
if actual != expected:
raise ValueError("예제 집계가 expected.json의 손계산 기대값과 다릅니다.")
OUTPUT.mkdir()
with (OUTPUT / "summary.json").open("x", encoding="utf-8") as stream:
json.dump(actual, stream, ensure_ascii=False, indent=2)
stream.write("\n")
with (OUTPUT / "verification.txt").open("x", encoding="utf-8") as stream:
stream.write(f"unittest: {result.testsRun}개 통과\n예제 기대값: 일치\n외부 AI API 호출: 없음\n")
print(f"완료: {actual['row_count']}행, 수량 {actual['quantity']}, 금액 {actual['amount']}")
print(OUTPUT)
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except (OSError, ValueError, csv.Error) as error:
print(f"중지: {error}", file=sys.stderr)
raise SystemExit(2)
O unit price é convertido em Decimal a partir da string, multiplicado por 100 para convertê-lo em integer units e depois somado. O amount resultante também é retornado como string com duas casas decimais. Essa é uma escolha adequada à two-decimal unit price rule do exemplo, não uma regra universal para todo cálculo numérico.
05Casos normais, de limite e de erro verificados pelos testes
Categoria
Tests integrados
O que verifica
Normal
One row, repeated item, leading and trailing spaces
Cálculo básico e grouping
Boundary
Empty input, quantity 0, upper limit
Definições em valores pequenos e grandes
Decimals
0.10 + 0.20 = 0.30
Representação e soma de amount
Error
Invalid quantity, unit price, blank item, columns, types
Invalid values não são aceitos silenciosamente
Verifique ok ao lado de cada test name e, no final, ‘Ran 12 tests’ e ‘OK’. A comparação com os CSV expected values passou somente quando você também vê ‘완료: 4행, 수량 6, 금액 11101.50’ (Done: 4 rows, quantity 6, amount 11101.50). Se apenas os unit tests passarem e o result diferir de expected.json, a execução padrão falha e não salva novos resultados.
bash
python example.py --test
--test repete apenas os unit tests e não cria outputs. Ele pode ser usado mesmo que uma results folder já exista, o que o torna adequado para verificações rápidas durante a edição da função. Em contraste, o comando padrão para sem sobrescrever outputs existentes.
06Experimente criar um teste com falha uma vez
Prepare uma cópia de example.py em uma pasta recém-extraída. Mantenha o arquivo original para poder restaurá-lo.
Na calculation line int(price * 100) * quantity, exclua apenas o último * quantity para criar um erro que ignora quantity.
Execute python example.py --test e verifique se tests como one-row quantity 3 e repeated-item falham.
Restaure a calculation line original e execute --test novamente para ver que todos os 12 passam.
O objetivo deste experimento é confirmar que os tests detectam erros. Durante a criação deste exemplo, o mesmo tipo de erro foi injetado em uma temporary copy para verificar que os tests falham e nenhum resultado é gravado. Ver uma falha significativa uma vez facilita evitar uma situação em que o test code executa, mas não verifica nada.
07Etapas para aplicar isso a uma função recebida de IA
Para código novo, primeiro fixe exemplos de input e output. Se alguma parte gravar em original files, limite-a a copies e separe primeiro a função que faz o cálculo. Prepare um conjunto de normal data, empty data, 0, repeated items e values que não devem ser permitidos, e calcule os expected values por conta própria.
Escreva as business rules da função como frases. Por exemplo, decida se returns são rejeitados ou calculados como negative amounts.
Escreva um small input e expected value para cada rule. Compare juntos overall total e per-item results.
Coloque o mesmo input na função em revisão e leia as differences nos results. Não altere primeiro os expected values para fazer as falhas desaparecerem.
Depois de executar novamente os existing tests com o revised code, mantenha também os novos error cases nos tests.
Se você substituir input.csv pelos seus próprios data, também deverá calcular e atualizar expected.json separadamente. Não conclua que uma divergência com os expected values é um code defect depois de alterar apenas o input. Verificar quais rules e quais data mudaram é onde começa a reproducible verification.
08Leia a mensagem de falha e restrinja a causa
Resultado
Significado
Próxima verificação
FAIL or FAILED
O calculated result difere do expected value do test
Leia o name do failed test e os dois values.
Stopped due to input rules
Um CSV value está fora do allowed range
Verifique a row indicada e os original data.
Differs from the hand-calculated expected value
A CSV aggregation não corresponde a expected.json
Verifique novamente tanto se os data mudaram quanto o hand calculation.
outputs already exists
Existe um successful result anterior
Execute apenas os checks com --test ou mova os results para outro lugar para preservá-los.
Passar nos tests deste exemplo é evidência para as rules declaradas. Não é uma medição do performance de um AI model real nem garantia de accuracy para todo trabalho contábil. Taxes, discounts, exchange rates, returns, multiple currencies e performance em large data precisam de rules e tests separados. Quanto mais failure cases você adicionar, mais claramente poderá explicar o intervalo em que o método se aplica.
Registro de execução e verificação
2026-09-19 · Windows 11 · CPython 3.12.14 · Sem pacotes adicionais · Executado em uma temporary copy da distribuição
12 tests integrados de unittest passaram
As 4 rows do CSV sintético correspondem ao expected value calculado manualmente de 11101.50
Para antes de criar resultados quando input e expected values não correspondem
Os tests detectaram um calculation error deliberado que ignora quantity
Foram confirmadas execuções repetidas de --test e preservação do SHA-256 original
Limites da verificação
Nenhuma API real de IA foi chamada.
Tax, exchange rate, returns e performance verification não estão incluídos.
Resultados da execução em Windows CPython 3.12.14.
O código de exemplo, os nomes de arquivos e as chaves de entrada são mantidos como no original. Consulte também os comandos e os procedimentos de conferência do texto traduzido.
Material de prática original · Guarde os arquivos originais separadamente antes de executar.
Fontes de referência
As explicações e os exemplos são de elaboração própria. Os comportamentos e conceitos relacionados podem ser consultados nas fontes oficiais abaixo.
Transforme “automatize isso” em uma descrição de tarefa executável. Anexe uma amostra sintética sem dados sensíveis e um resultado esperado verificado manualmente para completar uma solicitação de script que totaliza registros de trabalho por equipe.
Separe um resumo plausível em fatos, cálculos e interpretações. Recalcule proporções e médias a partir de dados mensais sintéticos e reescreva frases com fontes ausentes ou causas exageradas como afirmações que possam ser verificadas.
Trate uma regex gerada por IA como um rascunho, não como uma regra final. Monte uma pequena tabela de testes sintéticos, compare os resultados esperados com as correspondências reais, revise o padrão e salve um relatório de revisão antes de usá-lo em dados reais.
Trate uma consulta SQL gerada por IA como um rascunho e teste-a em um pequeno banco SQLite com respostas conhecidas. Compare o resultado da IA com uma tabela esperada calculada manualmente antes de usar a consulta em dados reais.