Sto lavorando su un framework di test open source .
Il 90% della mia base di codice ha una buona copertura di test. Il mio problema principale è il punto di ingresso della riga di comando . Questo modulo è nato come uno script molto breve per chiamare il modello di dominio (vedere la chiamata a _run_impl()
) e uscire con il codice 1 se l'esecuzione di test ha avuto esito negativo.
Non mi sembrava necessario testare quello script al momento in cui l'ho scritto, ma dal momento che il progetto ha funzionato, alcune piccole modifiche alla logica in questo file lo hanno portato a diventare piuttosto lungo:
import argparse
import os
import sys
from . import _run_impl # a function, in __init__.py, which calls into the domain model
from . import reporting # a sub-package concerned with writing output to the console
import colorama; colorama.init()
def cmd():
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--no-capture',
action='store_false',
dest='capture',
default=True,
help="Disable capturing of stdout during tests.")
parser.add_argument('-v', '--verbose',
action='store_true',
dest='verbose',
default=False,
help="Enable verbose progress reporting.")
parser.add_argument('--teamcity',
action='store_true',
dest='teamcity',
default=False,
help="Enable teamcity test reporting.")
parser.add_argument('--no-random',
action='store_false',
dest='shuffle',
default=True,
help="Disable test order randomisation.")
parser.add_argument('path',
action='store',
nargs='?',
default=os.getcwd(),
help="Path to the test file or directory to run. (default current directory)")
args = parser.parse_args()
if args.teamcity or "TEAMCITY_VERSION" in os.environ:
reporters = (reporting.teamcity.TeamCityReporter(sys.stdout),)
elif args.verbose:
reporters = (reporting.cli.ColouredReporter(sys.stdout),)
elif args.capture:
reporters = (
reporting.cli.DotsReporter(sys.stdout),
type("ColouredCapturingReporter", (reporting.cli.ColouredReporter, reporting.cli.StdOutCapturingReporter), {})(sys.stdout),
reporting.cli.TimedReporter(sys.stdout)
)
else:
reporters = (
reporting.cli.DotsReporter(sys.stdout),
type("ColouredCapturingReporter", (reporting.cli.ColouredReporter, reporting.cli.SummarisingReporter), {})(sys.stdout),
reporting.cli.TimedReporter(sys.stdout)
)
reporter = reporting.shared.ReporterManager(*reporters)
_run_impl(os.path.realpath(args.path), reporter, args.shuffle)
if reporter.failed:
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
cmd()
So che questo codice ha dei bug (per esempio, dovrebbe essere possibile catturare lo stdout dai test quando si esegue in modalità dettagliata), e ho perso la fiducia nella mia capacità di cambiare questo modulo senza rompere qualcosa. Quindi voglio scrivere alcuni test per questo - ma ho solo esperienza con lo sviluppo test-first, quindi non so da dove iniziare.
I test dovrebbero essere all'unità o al livello di integrazione? Devo prendere in giro il ArgumentParser
? Devo simulare il modulo reporting
? Devo simulare _run_impl
? Dovrei provare a portare l'intero modulo sotto test all'inizio, o semplicemente aggiungere test mentre aggiungo funzionalità? Devo refactoring per rendere questo metodo più testabile?
Addendum : Penso che una parte della mia confusione sia dovuta al fatto che questo è uno strato relativamente sottile in cima alla logica del business - è proprio lì per rendere possibile il calcio d'inizio test runner dalla riga di comando. Quindi mi sento confuso su ciò che costituisce il confine del servizio qui - in particolare, quello che dovrei e non dovrei prendere in giro.