Test unitari (NUnit/xUnit)
Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 67 di 70.
Sfida
FacileCompletiamo il tuo progetto Library System aggiungendo test unitari! I test sono essenziali per assicurarsi che il codice funzioni correttamente e continui a funzionare mentre apporti modifiche. Creerai un file di test dedicato per verificare le funzionalità principali del tuo sistema di gestione della biblioteca.
Continuerai a lavorare con la struttura esistente del tuo progetto, aggiungendo un nuovo file di test:
Book.cs: Mantieni la tua classe Book conId,Title,Author,IsAvailablee i metodiBorrow()eReturn().User.cs: Mantieni la tua classe User con il tracciamento dei prestiti, la costanteMaxBooks,CanBorrow()e i metodi per gestire i libri presi in prestito.Library.cs: Mantieni la tua classe Library con la logica dei prestiti, i metodi di ricerca e i metodiGetAllBooks()eGetAllUsers().LibraryTests.cs: Questo è il tuo nuovo file di test! Crea una classe di test che verifichi che il tuo sistema di gestione della biblioteca funzioni correttamente. Scriverai metodi di test per controllare diversi scenari e indicare se ogni test ha esito positivo o negativo.Program.cs: Il punto di ingresso che esegue i test e ne mostra i risultati.
La tua classe di test dovrebbe includere metodi che verificano questi scenari:
TestBookBorrow- Verifica che il prestito di un libro disponibile riesca e ne modifichi la disponibilitàTestBookBorrowUnavailable- Verifica che il tentativo di prendere in prestito un libro già in prestito fallisca nel modo previstoTestUserBorrowingLimit- Verifica che gli utenti non possano prendere in prestito più di 3 libriTestBookReturn- Verifica che la restituzione di un libro preso in prestito funzioni correttamenteTestSearchByAuthor- Verifica che la ricerca per autore restituisca i libri corretti
Ogni metodo di test dovrebbe restituire un valore booleano che indichi se il test è stato superato. Crea un semplice esecutore di test che esegua tutti i test e ne stampi i risultati.
Riceverai i seguenti input:
- Numero di scenari di test da eseguire (1-5, corrispondenti ai test elencati sopra)
Per ogni test eseguito, stampa il risultato nel formato:
{TestName}: {PASS|FAIL}Al termine di tutti i test, stampa un riepilogo:
--- Test Summary ---
Passed: {count}
Failed: {count}
Total: {count}Per esempio, se l'input è:
3L'output dovrebbe essere:
TestBookBorrow: PASS
TestBookBorrowUnavailable: PASS
TestUserBorrowingLimit: PASS
--- Test Summary ---
Passed: 3
Failed: 0
Total: 3Un altro esempio con tutti e 5 i test:
5L'output dovrebbe essere:
TestBookBorrow: PASS
TestBookBorrowUnavailable: PASS
TestUserBorrowingLimit: PASS
TestBookReturn: PASS
TestSearchByAuthor: PASS
--- Test Summary ---
Passed: 5
Failed: 0
Total: 5I tuoi test dovrebbero creare nuove istanze di Book, User e Library per ogni test, così da garantire l'isolamento. In questo modo, lo stato di un test non influisce su un altro. Considera ogni test come una verifica autonoma di un comportamento specifico del tuo sistema!
Provalo tu
using System;
using System.Collections.Generic;
namespace LibrarySystem
{
class Program
{
public static void Main(string[] args)
{
// Read library name
string libraryName = Console.ReadLine();
// Create a Library instance with the library name
Library library = new Library(libraryName);
// Read number of commands
int numCommands = Convert.ToInt32(Console.ReadLine());
// Process commands
for (int i = 0; i < numCommands; i++)
{
string commandLine = Console.ReadLine();
string[] parts = commandLine.Split('|');
string command = parts[0];
if (command == "ADD_BOOK")
{
string bookId = parts[1];
string bookTitle = parts[2];
string bookAuthor = parts[3];
Book book = new Book(bookId, bookTitle, bookAuthor);
library.AddBook(book);
Console.WriteLine($"Added: {bookTitle}");
}
else if (command == "ADD_USER")
{
string userName = parts[1];
int memberId = Convert.ToInt32(parts[2]);
User user = new User(userName, memberId);
library.RegisterUser(user);
Console.WriteLine($"Registered: {userName}");
}
else if (command == "BORROW")
{
string bookId = parts[1];
int memberId = Convert.ToInt32(parts[2]);
string result = library.BorrowBook(bookId, memberId);
Console.WriteLine(result);
}
else if (command == "RETURN")
{
string bookId = parts[1];
int memberId = Convert.ToInt32(parts[2]);
string result = library.ReturnBook(bookId, memberId);
Console.WriteLine(result);
}
else if (command == "SEARCH")
{
string searchType = parts[1];
List<Book> results = new List<Book>();
if (searchType == "title")
{
string searchValue = parts[2];
results = library.SearchByTitle(searchValue);
}
else if (searchType == "author")
{
string searchValue = parts[2];
results = library.GetBooksByAuthor(searchValue);
}
else if (searchType == "available")
{
results = library.GetAvailableBooks();
}
else if (searchType == "borrowed")
{
results = library.GetBorrowedBooks();
}
if (results.Count == 0)
{
Console.WriteLine("No books found");
}
else
{
foreach (Book book in results)
{
Console.WriteLine($"{book.Title} by {book.Author}");
}
}
}
else if (command == "STATUS")
{
List<Book> allBooks = library.GetAllBooks();
List<Book> availableBooks = library.GetAvailableBooks();
List<User> allUsers = library.GetAllUsers();
List<Book> borrowedBooks = library.GetBorrowedBooks();
Console.WriteLine("--- Library Status ---");
Console.WriteLine($"Total Books: {allBooks.Count}");
Console.WriteLine($"Available: {availableBooks.Count}");
Console.WriteLine($"Total Users: {allUsers.Count}");
Console.WriteLine($"Books Borrowed: {borrowedBooks.Count}");
}
}
}
}
}
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniNamespace e direttiveIntroduzione a classi e oggettiLa parola chiave "this"Metodi e parametriCampi e proprietàCostruttoriInizializzatori di oggettiRiepilogo - Calcolatrice semplice4Ereditarietà
Sintassi di base dell'ereditarietà (:)La parola chiave 'base'Parole chiave virtual e overrideClassi sealedLa classe base 'object'Riepilogo - Gerarchia dei dipendenti7Funzionalità avanzate
Sovraccarico degli operatoriIndicizzatori (this[])Override di ToString()Metodi di estensioneRiepilogo - Lista personalizzata10Pattern di progettazione Parte 1
Introduzione ai pattern di progettazioneSingleton thread-safePattern FactoryPattern Observer (eventi)Pattern Strategy2Proprietà e membri statici
Proprietà implementate automaticamenteProprietà di sola lettura e di sola scritturaCampi e metodi staticiClassi staticheMembri con corpo di espressione5Polimorfismo e interfacce
Polimorfismo a compile time e runtimeInterfaccia o classe astrattaInterfacce multipleInterfacce espliciteUpcasting e downcastingRipasso: calcolatore di forme8Concetti avanzati di programmazione a oggetti
Composizione invece dell'ereditarietàTipi generici (classi e metodi)Delegati ed eventiAttributi e reflectionIDisposable e istruzione usingNozioni di base sull'iniezione delle dipendenze11Pattern di progettazione, parte 2
Pattern del ComandoPattern dell’AdattatorePattern del DecoratorePattern Template MethodPattern dello StatoPattern Composito3Architettura delle classi
Dati di istanza vs staticiParole chiave 'readonly' e 'const'Campi di supportoRiepilogo - Gestore di conti bancari6Incapsulamento
Modificatori di accessoProprietà per l'incapsulamentoImplementazione dell'occultamento dei datiModelli di immutabilitàRiepilogo - Registri degli studenti9Argomenti variabili
La parola chiave 'params'Parametri opzionaliArgomenti con nomeOverloading dei metodi12Progetto: Sistema bibliotecario
Struttura del progettoModelli di libri e utentiLogica del sistema di prestitoRicerca con LINQInterfaccia console / interfaccia amministratoreTest unitari (NUnit/xUnit)Esercitati da solo: Compilatore C# online