I test runner hanno la sola responsabilità di prendere una soluzione, eseguire tutti i test e restituire un output standardizzato. Tutte le interazioni con il sito di Exercism sono gestite automaticamente e non fanno parte di questa specifica.
two-fer)./tmp per i file temporanei (ad esempio per compilare i sorgenti).results.json nella directory di output.Il test runner ha a disposizione il 100% della CPU e 3 GB di memoria per una finestra di 20 secondi per ogni soluzione. Dopo 20 secondi, il processo viene interrotto e viene segnalato un timeout.
Ti consigliamo vivamente di seguire il nostro documento sulle best practice per le prestazioni per ridurre il rischio di timeout.
I seguenti campi sono supportati nei file results.json:
chiave:
version, tipo:number, presenza: obbligatoria
version: 1, 2, 3
La versione della specifica a cui questo file aderisce:
1: per i track il cui test runner non può fornire informazioni sui singoli test.2: per i track il cui test runner può fornire informazioni sui singoli test. Versione minima richiesta per i track con esercizi sui concetti.3: per i track il cui test runner può collegare singoli test a un compito.chiave:
status, tipo:string, presenza: obbligatoria
version: 1, 2, 3
I seguenti stati complessivi sono validi:
pass: tutti i test sono passatifail: almeno un test ha lo stato fail o error
error: nessun test è stato eseguito (di solito significa un errore di compilazione o un errore di sintassi)Lo stato error va usato solo se tutti i test sono andati in errore.
Per i linguaggi compilati, questo di solito deriva dal fatto che il codice non riesce a compilare.
Per i linguaggi interpretati, si tratta di un errore a runtime, come un errore di sintassi che impedisce al file di essere analizzato.
chiave:
message, tipo:string, presenza: obbligatoria sestatus=error, oppure quandostatus=faileversion=1
version: 1, 2, 3
Quando lo stato è error (nessun test è stato eseguito correttamente), va fornita la chiave message di livello superiore. Deve mostrare all'utente l'errore che si è verificato. Dato che è l'unica informazione che l'utente riceverà su come fare debug del proprio problema, deve essere il più chiaro possibile:
<solution-dir>/relative/path invece di /full/path/to, perché quest'ultimo includerebbe dati specifici di ECR che non sono utiliIn Ruby, nel caso di un errore di sintassi, forniamo l'errore a runtime e lo stack trace. Nei linguaggi compilati, va fornito l'errore di compilazione.
Il valore di message di livello superiore è limitato a 65535 caratteri.
La lunghezza massima effettiva è inferiore se il valore contiene caratteri multibyte.
Quando lo stato non è error, imposta il valore su null oppure ometti del tutto la chiave.
chiave:
tests, tipo:array, presenza: obbligatoria sestatus=failoppurestatus=pass
version: 2, 3
È un array dei risultati dei test, specificati nella sezione "Per singolo test" qui sotto.
I test DEVONO essere restituiti nell'ordine in cui sono specificati nel file dei test. Per i linguaggi che eseguono i test in ordine casuale, questo può significare riordinare i risultati secondo l'ordine specificato nel file dei test.
La ragione è che agli studenti viene mostrato solo il primo fallimento, quindi è importante che venga mostrato quello giusto. Dato che di solito i test sono ordinati nel file dei test seguendo la logica del TDD, e dato che per gli esercizi di pratica gli studenti vedono il file dei test nell'editor, allineare i risultati al file dei test è fondamentale.
chiave:
name, tipo:string, presenza: obbligatoria
version: 2, 3
È il nome del test in un formato leggibile da una persona.
chiave:
test_code, tipo:string, presenza: obbligatoria se l'esercizio è un esercizio sui concetti
version: 2, 3
Questo campo DEVE essere presente per gli esercizi sui concetti e DOVREBBE esserlo per gli esercizi di pratica.
La differenza in questo requisito deriva dal fatto che negli esercizi sui concetti i test non vengono mostrati agli studenti, quindi risolvere l'esercizio potrebbe essere impossibile senza che venga mostrato test_code, mentre negli esercizi di pratica i test vengono mostrati.
È il corpo del comando che viene testato. Ad esempio, il seguente test Ruby:
def test_duplicate_items_uniqs_list
cart = ShoppingCart.new
cart.add(:STARIC)
cart.add(:MEDNEW)
cart.add(:MEDNEW)
assert_equal 'Newspaper, Rice', cart.items_list
end
dovrebbe restituire un valore test_code pari a:
"cart = ShoppingCart.new
cart.add(:STARIC)
cart.add(:MEDNEW)
cart.add(:MEDNEW)
assert_equal 'Newspaper, Rice', cart.items_list"
(con le interruzioni di riga sostituite da \n per rendere valido il JSON).
chiave:
status, tipo:string, presenza: obbligatoria
version: 2, 3
I seguenti stati per singolo test sono validi:
pass: il test è passatofail: il test è fallitoerror: il test è andato in errore, cioè non ha restituito un valorechiave:
message, tipo:string, presenza: obbligatoria sestatusèfailoerror
version: 2, 3
La chiave message per singolo test serve a restituire i risultati di un test il cui status è fail o error. Deve essere il più possibile leggibile da una persona. Qualunque cosa venga scritta qui sarà mostrata allo studente quando il suo test non passa. Se non c'è alcun messaggio di fallimento o di errore del test, imposta il valore su null oppure ometti del tutto la chiave. È anche consentito mostrare qui l'output della suite di test. Il valore di message non ha limiti di lunghezza.
chiave:
output, tipo:string, presenza: opzionale
version: 2, 3
La chiave output per singolo test dovrebbe essere usata per memorizzare e mostrare tutto ciò che un utente produce intenzionalmente per un test.
puts in Ruby, print in Python o Debug.WriteLine in C#), sia fornire un metodo che l'utente può usare (ad esempio, il test runner di Ruby mette a disposizione dell'utente un metodo debug globale che può usare, con le stesse caratteristiche del metodo puts standard).chiave:
task_id, tipo:number, presenza: opzionale
version: 3
Collega un test a un compito specifico tramite l'ID del compito, cioè il numero usato all'inizio dell'intestazione del compito. Collega un test a un compito solo se può essere collegato esattamente a un compito.
Al momento, solo gli esercizi sui concetti hanno compiti ben definiti a cui collegare i test, ma in futuro le cose potrebbero cambiare.
Ad esempio, considera il seguente file instructions.md:
# Instructions
You're going to write some code to help Lucian cook an exquisite lasagna from his favorite cook book.
## 1. Define the expected oven time in minutes
...
## 2. Calculate the remaining oven time in minutes
...
Queste istruzioni definivano due compiti:
Il file results.json potrebbe quindi avere una voce come questa:
{
"name": "Expected oven time in minutes",
"status": "pass",
"task_id": 1,
"test_code": "Assert.Equal(40, Lasagna.ExpectedMinutesInOven());"
}
Questo test ora è collegato al primo compito: «Definire il tempo di cottura previsto in minuti». Nota che il nome non deve necessariamente corrispondere alla descrizione del compito.
Ci sono vari modi in cui i track potrebbero implementarlo:
.meta/config.json dell'esercizio) e unire queste informazioni nel file results.json generato.Questi sono esempi di come può apparire un file results.json valido per le diverse versioni:
{
"version": 1,
"status": "fail",
"message": "Failed: test_answer\nExpected: 42, actual: 3"
}
{
"version": 2,
"status": "fail",
"message": null,
"tests": [
{
"name": "Test that the thing works",
"status": "fail",
"message": "Expected 42 but got 123123",
"output": "Debugging information output by the user",
"test_code": "assert_equal 42, answerToTheUltimateQuestion()"
}
]
}
{
"version": 3,
"status": "fail",
"message": null,
"tests": [
{
"name": "Test that the thing works",
"status": "fail",
"message": "Expected 42 but got 123123",
"output": "Debugging information output by the user",
"test_code": "assert_equal 42, answerToTheUltimateQuestion()",
"task_id": 1
}
]
}
Quando la soluzione di uno studente non supera un test, dovrebbe mostrare qualcosa come:
Test Code:
<test_code>
Test Result:
<message>
Quando la soluzione supera un test, dovrebbe mostrare qualcosa come:
Test Code:
<test_code>
Tutte le strade portano a Roma e non esiste un modello prestabilito per arrivarci. Finora sono stati adottati diversi approcci: