Η γεννήτρια δοκιμών είναι ένα κομμάτι λογισμικού ειδικό για κάθε track, που δημιουργεί αυτόματα τις δοκιμές μιας άσκησης εξάσκησης. Αυτό γίνεται μετατρέποντας τα JSON test cases της άσκησης σε δοκιμές στη γλώσσα προγραμματισμού του track.
Μερικά από τα οφέλη μιας γεννήτριας δοκιμών είναι:
Σε γενικές γραμμές, τρέχεις μια γεννήτρια δοκιμών για έναν από τους εξής λόγους:
Όταν προσθέτεις μια γεννήτρια δοκιμών για μια νέα άσκηση, μπορείς να δημιουργήσεις τα αρχεία δοκιμών της. Αν η ίδια η γεννήτρια δοκιμών έχει ήδη υλοποιηθεί, η δημιουργία των δοκιμών για τη νέα άσκηση θα είναι (πολύ) λιγότερη δουλειά από το να τις γράψεις από την αρχή.
Μόλις μια άσκηση αποκτήσει γεννήτρια δοκιμών, μπορείς να την ξανατρέξεις για να ενημερώσεις/συγχρονίσεις την άσκηση με τα τελευταία κανονικά δεδομένα της. Συνιστούμε να το κάνεις αυτό περιοδικά, για να ελέγχεις αν υπάρχουν προβληματικά test cases που χρειάζονται ενημέρωση ή νέες δοκιμές που θέλεις να συμπεριλάβεις.
Υπάρχουν δύο πιθανά σημεία εκκίνησης όταν υλοποιείς μια γεννήτρια δοκιμών για μια άσκηση:
Αν υπάρχουν ήδη δοκιμές, υλοποίησε τη γεννήτρια δοκιμών έτσι ώστε οι δοκιμές που παράγει να μην σπάνε τις υπάρχουσες λύσεις.
Σε γενικές γραμμές, τα αρχεία δοκιμών δημιουργούνται με έναν από τους εξής τρόπους:
Έχουμε διαπιστώσει ότι η προσέγγιση με κώδικα οδηγεί σε αρκετά περίπλοκο κώδικα για τη γεννήτρια δοκιμών, ενώ η προσέγγιση με πρότυπα είναι πιο απλή.
Αυτό που προτείνουμε είναι η εξής ροή:
include = false στο αρχείο tests.toml της άσκησηςΤο βασικό πλεονέκτημα αυτής της ρύθμισης είναι ότι κάθε άσκηση έχει το δικό της πρότυπο, το οποίο:
Όταν σχεδιάζεις τη γεννήτρια δοκιμών, προσπάθησε να:
Η γεννήτρια δοκιμών συνήθως (κατά κύριο λόγο) γράφεται στη γλώσσα του track.
Ενώ είσαι ελεύθερος να χρησιμοποιήσεις άλλες γλώσσες, κάθε επιπλέον γλώσσα θα κάνει πιο δύσκολη τη συντήρηση ή τη συνεισφορά στο track. Γι' αυτό, συνιστούμε να χρησιμοποιείς τη γλώσσα του track όπου είναι εφικτό, γιατί κάνει τη συντήρηση ή τη συνεισφορά πιο εύκολη.
Αν το track σου διαθέτει εργαλεία για μορφοποίηση κώδικα, σκέψου να το τρέξεις ως βήμα μετα-επεξεργασίας αφού αποδώσεις το πρότυπό σου.
Τα βασικά δεδομένα με τα οποία δουλεύει η γεννήτρια δοκιμών είναι το canonical-data.json file μιας άσκησης.
Αυτό το αρχείο ορίζεται στο αποθετήριο exercism/problem-specifications, το οποίο ορίζει κοινά μεταδεδομένα για πολλές ασκήσεις στο Exercism.
Δεν έχουν όλες οι ασκήσεις αρχείο canonical-data.json!
Αν δεν έχουν, θα χρειαστεί να δημιουργήσεις τις δοκιμές χειροκίνητα, αφού δεν υπάρχουν δεδομένα για να δουλέψει η γεννήτρια δοκιμών.
Τα κανονικά δεδομένα ορίζονται σε ένα αντικείμενο JSON.
Αυτό το αντικείμενο περιέχει ένα πεδίο "cases" που περιέχει τα test cases.
Αυτά τα test cases (κανονικά) αντιστοιχούν ένα προς ένα σε δοκιμές στο track σου.
Κάθε test case έχει μερικές ιδιότητες, με σημαντικότερες την περιγραφή, το πεδίο property, την τιμή (ή τις τιμές) εισόδου και την αναμενόμενη τιμή. Ακολουθεί ένα (μερικό) παράδειγμα του αρχείου canonical-data.json της άσκησης leap:
{
"exercise": "leap",
"cases": [
{
"uuid": "6466b30d-519c-438e-935d-388224ab5223",
"description": "year not divisible by 4 in common year",
"property": "leapYear",
"input": {
"year": 2015
},
"expected": false
},
{
"uuid": "4fe9b84c-8e65-489e-970b-856d60b8b78e",
"description": "year divisible by 4, not divisible by 100 in leap year",
"property": "leapYear",
"input": {
"year": 1996
},
"expected": true
}
]
}
Η κύρια ευθύνη της γεννήτριας δοκιμών είναι να μετατρέψει αυτά τα δεδομένα JSON σε δοκιμές ειδικές για το track. Να πώς θα μπορούσε το παραπάνω JSON να μετατραπεί σε κώδικα δοκιμών Nim:
import unittest
import leap
suite "Leap":
test "year not divisible by 4 in common year":
check isLeapYear(2015) == false
test "year divisible by 4, not divisible by 100 in leap year":
check isLeapYear(1996) == true
Η δομή του αρχείου canonical-data.json είναι καλά τεκμηριωμένη και διαθέτει επίσης ορισμό σχήματος JSON.
Κάποιες ασκήσεις χρησιμοποιούν εμφώλευση στα κανονικά δεδομένα τους.
Αυτό σημαίνει ότι κάθε στοιχείο σε έναν πίνακα cases μπορεί να είναι είτε:
Μπορείς να αναγνωρίσεις τον τύπο ενός στοιχείου ελέγχοντας αν υπάρχουν πεδία που είναι αποκλειστικά για έναν τύπο στοιχείου.
Πιθανώς ο καλύτερος τρόπος για να το κάνεις αυτό είναι να χρησιμοποιήσεις το κλειδί "cases", το οποίο υπάρχει μόνο στις ομάδες test cases.
Ακολουθεί ένα παράδειγμα εμφωλευμένων test cases:
{
"cases": [
{
"uuid": "e9c93a78-c536-4750-a336-94583d23fafa",
"description": "data is retained",
"property": "data",
"input": {
"treeData": ["4"]
},
"expected": {
"data": "4",
"left": null,
"right": null
}
},
{
"description": "insert data at proper node",
"cases": [
{
"uuid": "7a95c9e8-69f6-476a-b0c4-4170cb3f7c91",
"description": "smaller number at left node",
"property": "data",
"input": {
"treeData": ["4", "2"]
},
"expected": {
"data": "4",
"left": {
"data": "2",
"left": null,
"right": null
},
"right": null
}
}
]
}
]
}
Αν το track σου δεν υποστηρίζει ομαδοποίηση δοκιμών, θα χρειαστεί να:
cases ώστε να καταλήξεις μόνο στα πιο εσωτερικά (φύλλα) test casesΤα περιεχόμενα των κλειδιών input και expected ενός test case ποικίλλουν σε μεγάλο βαθμό.
Στις περισσότερες περιπτώσεις είναι βαθμωτές τιμές (όπως αριθμοί, Boolean (λογική τιμή) ή συμβολοσειρές) ή απλά αντικείμενα.
Ωστόσο, περιστασιακά θα συναντήσεις και πιο σύνθετες τιμές που πιθανότατα χρειάζονται λίγη προεπεξεργασία, όπως lambdas σε ψευδοκώδικα, λίστες πράξεων που εκτελούνται στον κώδικα του μαθητή και άλλα.
Τα test cases έχουν ένα προαιρετικό πεδίο scenarios.
Αυτό το πεδίο μπορεί να χρησιμοποιηθεί από τη γεννήτρια δοκιμών για να χειριστεί ειδικά ορισμένα test cases.
Η πιο συνηθισμένη περίπτωση χρήσης είναι να αγνοήσεις ορισμένους τύπους δοκιμών, για παράδειγμα δοκιμές με το σενάριο "unicode", καθώς η γλώσσα του track σου μπορεί να μην υποστηρίζει Unicode.
Την πλήρη λίστα σεναρίων θα τη βρεις εδώ.
Υπάρχουν μερικές επιλογές για να διαβάσεις τα αρχεία canonical-data.json:
problem-specifications (π.χ. https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/leap/canonical-data.json).problem-specifications ως Git submodule στο αποθετήριο του track.configlet.
Η θέση εξαρτάται από το σύστημα του χρήστη, αλλά μπορείς να χρησιμοποιήσεις την εντολή configlet info -o -v d | head -1 | cut -d " " -f 5 για να βρεις τη θέση προγραμματιστικά.Αν το track σου θέλει να προσθέσει επιπλέον test cases ειδικά για το track (που δεν υπάρχουν στα κανονικά δεδομένα), μια επιλογή είναι να δημιουργήσεις ένα αρχείο additional-test-cases.json, το οποίο η γεννήτρια δοκιμών μπορεί στη συνέχεια να συγχωνεύσει με το αρχείο canonical-data.json πριν το περάσει στο πρότυπο για απόδοση.
Η μηχανή προτύπων που θα χρησιμοποιήσεις θα είναι πιθανότατα ειδική για το track. Ιδανικά, θέλεις τα πρότυπά σου να είναι όσο πιο απλά γίνεται, οπότε μην ανησυχείς για την επανάληψη κώδικα και τα παρόμοια.
Τα ίδια τα πρότυπα θα παίρνουν τα δεδομένα τους από τη γεννήτρια δοκιμών, η οποία κάνει επανάληψη πάνω τους για να τα αποδώσει.
Για να κρατήσεις τα πρότυπα απλά, μπορεί να σου φανεί χρήσιμο να κάνεις λίγη προεπεξεργασία στην πλευρά της γεννήτριας δοκιμών ή να ορίσεις κάποια "φίλτρα" ή όποιον άλλο μηχανισμό επέκτασης επιτρέπουν τα πρότυπά σου.
Το configlet είναι το βασικό εργαλείο συντήρησης ενός track και μπορείς να το χρησιμοποιήσεις για να:
bin/configlet create --practice-exercise <slug>
tests.toml μιας υπάρχουσας άσκησης: τρέξε bin/configlet sync --tests --update --exercise <slug>
Αυτό κάνει το configlet ένα εξαιρετικό εργαλείο για χρήση σε συνδυασμό με τη γεννήτρια δοκιμών, δημιουργώντας πραγματικά ισχυρές ροές εργασίας.
Θα θέλεις η χρήση της γεννήτριας δοκιμών να είναι και εύκολη και ισχυρή. Για αυτό, συνιστούμε να δημιουργήσεις ένα ή περισσότερα αρχεία script.
Είσαι ελεύθερος να επιλέξεις όποια μορφή αρχείου script ταιριάζει καλύτερα στο track σου. Τα shell scripts και τα PowerShell scripts είναι συνηθισμένες επιλογές που μπορούν να λειτουργήσουν καλά και οι δύο.
Ακολουθεί ένα παράδειγμα shell script που συνδυάζει το configlet και μια γεννήτρια δοκιμών για να στήσεις γρήγορα μια νέα άσκηση:
bin/fetch-configlet
bin/configlet create --practice-exercise <slug>
path/to/test-generator <slug>
Πριν αρχίσεις να φτιάχνεις μια γεννήτρια δοκιμών, σου προτείνουμε να ρίξεις μια ματιά σε μερικές υπάρχουσες γεννήτριες δοκιμών, για να πάρεις μια ιδέα για το πώς τις έχουν υλοποιήσει άλλα tracks:
Αν έχεις απορίες, το forum είναι το καλύτερο μέρος για να τις ρωτήσεις. Μπορεί επίσης να σου φανούν χρήσιμες οι συζητήσεις στο forum γύρω από τις γεννήτριες δοκιμών της Rust και της JavaScript.
Συνιστούμε να φτιάχνεις τη γεννήτρια δοκιμών σταδιακά, ξεκινώντας με ένα ελάχιστο βιώσιμο προϊόν.
Μια στοιχειώδης έκδοση θα διάβαζε το canonical-data.json μιας άσκησης και θα περνούσε απλώς αυτά τα δεδομένα στο πρότυπο.
Ξεκίνα εστιάζοντας σε μία μόνο άσκηση, κατά προτίμηση κάποια απλή, όπως η άσκηση leap.
Μόνο όταν αυτό δουλέψει θα πρέπει να προσθέσεις σταδιακά περισσότερες ασκήσεις.
Και προσπάθησε να κρατήσεις τη γεννήτρια δοκιμών όσο πιο απλή γίνεται.
Ιδανικά, ένας συνεισφέρων θα μπορούσε απλώς να επικολλήσει/τροποποιήσει ένα υπάρχον πρότυπο, χωρίς να χρειάζεται να καταλάβει πώς λειτουργεί εσωτερικά η γεννήτρια δοκιμών.
Το πώς θα χρησιμοποιήσεις ή θα συνεισφέρεις σε μια γεννήτρια δοκιμών εξαρτάται από το track.
Ψάξε για οδηγίες στο README.md, στο CONTRIBUTING.md του track ή στον κατάλογο του κώδικα της γεννήτριας δοκιμών.