Εισαγωγή
Η πρακτική του Unit Testing, δεν αποτελεί Agile «εφεύρεση» ούτε αποκλειστικότητα των Agile ομάδων. Αντιθέτως προϋπήρχε όπως πολλές άλλες. Η διαφορά, ωστόσο μιας agile ομάδα ανάπτυξης λογισμικού είναι ο τρόπος που την υλοποιεί και πως αυτή συνδυάζεται με άλλες πρακτικές και τεχνικές. Για το λόγο αυτό, αλλά και χάρις την εύκολη εφαρμογή της, η πρακτική του Unit Testing, βρίσκεται στις πρώτες θέσεις της λίστας των πρακτικών που υιοθετούνται άμεσα από τις περισσότερες ομάδες που προσπαθούν να ακολουθήσουν μία Agile προσέγγιση στην ανάπτυξη λογισμικού.
Τι σημαίνει λοιπόν Unit Testing. Είναι η μέθοδος με την οποία διαπιστώνεται αν οι αυτόνομες μονάδες λογισμικού πληρούν τις τεχνικές και επιχειρησιακές προδιαγραφές που καλούνται να υλοποιήσουν. Με λίγο πιο τεχνικούς όρους είναι τα «σενάρια ελέγχου» που πιστοποιούν ότι όλες οι μέθοδοι μίας κλάσης (άρα και η κλάση) είναι έτοιμες προς ολοκλήρωση με το υπόλοιπο σύστημα. Πριν αναλυθεί γιατί, πως και πότε πρέπει να αναπτύσσονται τα unit tests, είναι χρήσιμο να αποσαφηνιστούν μερικές έννοιες και να απομυθοποιηθούν καταστάσεις σχετικά με το testing.
Μύθοι και έννοιες
Μία ατέλεια λογισμικού ή αλλιώς ένα σφάλμα, ή αλλιώς ένα bug (δεν έχει σημασία ο όρος) συμβαίνει όταν
- Το λογισμικό δεν κάνει κάτι, το οποίο οι προδιαγραφές αναφέρουν ότι θα έπρεπε να κάνει
- Το λογισμικό κάνει κάτι, το οποίο οι προδιαγραφές αναφέρουν ότι δε θα έπρεπε να κάνει
- Το λογισμικό κάνει κάτι, το οποίο οι προδιαγραφές δεν αναφέρουν
- Το λογισμικό δεν κάνει κάτι, το οποίο οι προδιαγραφές δεν αναφέρουν αλλά θα έπρεπε να το αναφέρουν
- Το λογισμικό είναι δυσνόητο, δύσκολο στη χρήση του, αργό ή στα μάτια του tester ή του τελικού χειριστή δε φαίνεται σωστό
Είναι αδύνατον να ελεγχθεί πλήρως (100%) ένα σύστημα:
- Ο αριθμός των πιθανών δεδομένων εισόδου και εξόδου είναι απεριόριστος
- Ο αριθμός των διαφορετικών τρόπων χρήσεων ενός λογισμικού ( software paths) είναι επίσης πολύ μεγάλος
- Οι λειτουργικές προδιαγραφές είναι υποκειμενικές και αλλάζουν διαρκώς.
To Testing, ειδικότερα το Unit Testing, δεν αποδεικνύει ότι έχουν εξαλειφθεί όλες οι ατέλειες του λογισμικού.
Όταν εμφανίζεται μία ατέλεια σε ένα τμήμα κώδικα, τότε είναι σίγουρο ότι υπάρχουν εκεί κοντά ακόμα περισσότερες ατέλειες. Γιατί όμως?
- Οι developers έχουν κι αυτοί άσχημες ημέρες, όπως όλοι οι άνθρωποι.
- Οι developers, όπως όλοι οι άνθρωποι, συνηθίζουν να κάνουν το ίδιο λάθος.
- Συνήθως μία ατέλεια που ανακαλύπτεται είναι μόνο η «κορυφή του παγόβουνου»
Η θέση του Unit Testing στα επίπεδα ελέγχου ενός συστήματος.
Όπως φαίνεται στο παρακάτω σχήμα το Unit Testing αποτελεί το πρώτο «ανάχωμα» στη συνεχή μάχη με τις ατέλειες του λογισμικού. Τα Unit Tests γράφονται κατά κανόνα από τους developers που αναπτύσσουν τον αντίστοιχο κώδικα και σε σπάνιες περιπτώσεις από white-box testers.
Η χρονική στιγμή που πρέπει να γράφονται τα unit tests έχει άμεση εξάρτηση με το αν εφαρμόζεται η πρακτική του test-driven development, για την οποία θα αναφερθώ σε μελλοντικό blog. Αν λοιπόν μία ομάδα ανάπτυξης ακολουθεί test-driven development τότε τα tests γράφονται πριν από τον κώδικα, διαφορετικά αναπτύσσονται συνήθως παράλληλα με τον κώδικα ή στο τέλος. Η σύγκριση, ωστόσο, των παραπάνω τεχνικών δεν αποτελεί αντικείμενο του παρόντος Blog. Όποτε λοιπόν έχουμε αμφιβολία για το πώς ο κώδικάς μας συμπεριφέρεται ή όποτε θέλουμε να πιστοποιήσουμε ότι κάνει αυτό που περιμένουμε, γράφουμε ένα unit test. Η αξία των Unit Tests είναι ανεκτίμητη επειδή άπαξ και αυτοματοποιηθούν μπορούμε να τα εκτελούμε κάθε φορά που κάνουμε μία αλλαγή στον κώδικα ώστε να ξέρουμε άμεσα και αξιόπιστα αν έχουμε χαλάσει κάτι που ήδη «έπαιζε σωστά». Ένα Agile project, θα έχει εκατοντάδες, αν όχι χιλιάδες unit tests, τα οποία διατρέχουν όλο το λογισμικό ελέγχοντας ότι αφορά την επιχειρησιακή λογική του (business logic).
Χαρακτηριστικά ενός καλού Unit Test
- Θα πρέπει να είναι αυτοματοποιημένο και να μπορεί να επαναληφθεί όποτε απαιτείται.
- Θα πρέπει να είναι εύκολο στην υλοποίηση και στη συντήρησή του
- Άπαξ και αναπτύχθηκε μια φορά θα πρέπει να είναι διαθέσιμο για μελλοντική χρήση
- Οποιοσδήποτε θα πρέπει να μπορεί να τρέξει και να δει τα αποτελέσματά του
- Θα πρέπει να ακολουθεί τους ίδιους κανόνες σχεδίασης με το λογισμικό που ελέγχει ώστε να αποφεύγονται σφάλματα μέσα στα ίδια τα tests.
- Θα πρέπει να είναι γρήγορο και αξιόπιστο.
Τα οφέλη της εφαρμογής της πρακτικής του Unit Testing
- Άμεση ανατροφοδότηση (feedback)
- Μόλις γίνονται αλλαγές στον κώδικα κι ένα unit test «χαλάει» (σταματάει δηλαδή να είναι επιτυχές), ο developer το μαθαίνει αμέσως και όχι μετά από μερικές εβδομάδες, όταν έχει φτάσει η έκδοση στην ομάδα ελέγχου, ομάδα υποστήριξης ή ακόμα χειρότερα στον πελάτη.
- Δραματική μείωση του κόστους ελέγχου μίας έκδοσης
- Αντί να χρειάζεται να γίνει χειροκίνητος έλεγχος όλων των λειτουργιών κάθε φορά που είναι έτοιμη μία έκδοση, σώζουμε δεκάδες ώρες, αυτοματοποιώντας τουλάχιστον τους ελέγχους για τις «εύκολες» λειτουργίες και αφιερώνουμε τον υπόλοιπο χρόνο στις πιο περίπλοκες.
- Δραματική μείωση του χρόνου αποσφαλμάτωσης
- Όταν αποτυγχάνει ένα Unit Test ο developer ξέρει ΑΚΡΙΒΩΣ σε ποιο σημείο του κώδικα υπάρχει η ατέλεια, χωρίς να χρειάζεται να διατρέψει εκατοντάδες γραμμές κώδικα αναζητώντας αυτή που το έχει προκαλέσει.
- Αύξηση αξιοπιστίας και άνεση στη διανομή σε ομάδες ελέγχου και υποστήριξης
- Η ύπαρξη μίας πλειάδας αυτοματοποιημένων ελέγχων παρέχει ένα επίπεδο ασφάλειας σε όλους τους εμπλεκόμενους σε ένα project. Αυτό δε σημαίνει, φυσικά, ότι κάθε έκδοση γίνεται αποδεκτή, μόνο και μόνο επειδή υπάρχουν τα unit tests, αλλά μας «απελευθερώνει» ώστε να αφοσιωθούμε στον λεπτομερή έλεγχο κρίσιμων και περίπλοκων λειτουργιών του λογισμικού.