Előadást letölteni
Az előadás letöltése folymat van. Kérjük, várjon
1
Dependency Injection Moq Feladat
Haladó Programozás Dependency Injection Moq Feladat OE-NIK HP 1
2
Jól tesztelni nehéz (ismétlés)
Legyenek a tesztek gyorsak Lassú tesztek folyamatos futtatása nem lehetséges => hibák késői kiderülését okozhatja Legyenek lehetőleg egymástól függetlenek Sorrend, időzítés stb. nem hathat ki az eredményre Ránézésre olvasható nevekkel A jól elkészített tesztlista dokumentálja a kód képességeit (requirement-listának fogható fel) Nem kell és nem is szabad minden inputlehetőséget lefedni Sokszor példákkal tesztelnek Corner case-ek megtalálása fontosabb Egyszerre egyetlen művelet, és egy osztály tesztelése Mindig függetlenül az éles adattól, ami változhat – tehát nem olvasunk éles adatbázist, éles settingsfájlt, stb. Osztályok függőségeit is helyettesítjük: Dependency Injection + fake függőségek, mockolás... (=> Moq) Ránézésre olvasható nevekkel: + ránézésre olvasható teszt is legyen Az egymástól való függetlenítés miatt akár kódduplikáció is simán megengedett
3
Dependency Injection Az osztályok függőségeit kívülről biztosítjuk – interfészek formájában A DI lehetővé teszi a fejlesztés előrehaladtával a függőség lecserélését – az interfész megtartása mellett Lehetővé teszi a „valódi” unit- („egység-”) tesztelést is Tesztelésnél szándékosan cseréljük a függőséget egy ismert, egyszerű, e célra létrehozott objektumra Osztály függetlenítése a függőségeitől („Mindig függetlenül az éles adattól” ... „Egyszerre egyetlen művelet, és egy osztály tesztelése”) Gyorsaság Komplex osztály helyett nagyon egyszerű csereobjektum, csak azokkal az aspektusokkal, amelyekről a teszt szól Függetlenség 1 teszt => 1 csereobjektum Ha a tesztet osztály esetleg írni akar az objektumba, az se gond Technikái: fake függőségek, mockolás, stb. A DI nem (elsősorban) teszt célú dolog, de a tesztelhetőség egy lényeges előny. A DI-t teljesen betartó kód írása bonyolult, a Main()-nek ismernie kéne minden függőséget? => IoC containerek
4
Constructor Injection
interface IMyDependency { string DoSomething(); } class MyClass private IMyDependency dependency; public MyClass(IMyDependency dependency) this.dependency = dependency; // metódusaiban: dependency.DoSomething() // használata IMyDependency myDependency; // értékadás... MyClass myClass = new MyClass(myDependency); OE-NIK HP
5
Method Injection, Setter Injection
class MyClass { public void DoSomethingUsingDependency(IMyDependency dependency) // ... dependency.DoSomething() ... } class MyClass { public IMyDependency Dependency { get; set; } // metódusaiban: dependency.DoSomething() } Constructor Injection – gyakori, ha sok helyen kell a függőség Method Injection – gyakori, ha egy helyen kell a függőség Setter Injection – ritka Mindenhol ellenőrizni kell, hogy be lett-e már állítva Többszálúság még több gondot okoz (nem lett-e újra null?) OE-NIK HP
6
Példa class MainWindowViewModel : INotifyPropertyChanged {
private IEmployeeBusinessLogic employeeBusinessLogic; // ... private Employee selectedEmployee; public Employee SelectedEmployee get { return selectedEmployee; } set selectedEmployee = value; RemainingVacationDays = employeeBusinessLogic.CalcRemainingVacationDays(value); OnPropertyChanged(); } private int remainingVacationDays; public int RemainingVacationDays get { return remainingVacationDays; } set { remainingVacationDays = value; OnPropertyChanged(); } OE-NIK HP
7
Fake-ek Azonos interfészt implementál a helyettesítendő objektummal, de semmilyen, vagy csak szándékosan egyszerűsítő, tesztcélú logikát tartalmaz class FakeEmployeeBusinessLogic : IEmployeeBusinessLogic { public int CalcRemainingVacationDays(Employee employee) if (employee == null) throw new NullReferenceException(); return 30; } OE-NIK HP
8
Fake-ek [TestFixture] class MainWindowViewModelTests { [Test]
public void SelectedEmployeeChanged_RemainingDaysChanged() MainWindowViewModel viewModel = new MainWindowViewModel(new FakeEmployeeBusinessLogic()); Employee testEmployee = new Employee(); viewModel.SelectedEmployee = testEmployee; Assert.That(viewModel.RemainingVacationDays, Is.EqualTo(30)); } public void SelectedEmployeeChangedToNull_RemainingDaysSetToZero() viewModel.RemainingVacationDays = 111; viewModel.SelectedEmployee = null; Assert.That(viewModel.RemainingVacationDays, Is.EqualTo(0)); OE-NIK HP
9
Mock-ok Azonos interfészt implementál a helyettesítendő objektummal – nincs logika, fix adat Általában lehetőséget ad a végrehajtódó logika megfigyelésére is Expectation-ök: „a DoSomething() függvény pontosan egyszer hívódott” Mocking framework segítségével szokás készíteni Mocking framework képességeitől függően a mock, fake, stub stb. különbség elmosódhat Nagyon gyakori, hogy egyszerűen fake-nek használják a mockokat (és nincs expectation-ellenőrzés) Az egyik legelterjedtebb .NET mocking framework: Moq Mock<IEmployeeBusinessLogic> mockBusinessLogic = new Mock<IEmployeeBusinessLogic>(); // mock elvárt viselkedésének beállítása... MainWindowViewModel viewModel = new MainWindowViewModel(mockBusinessLogic.Object); OE-NIK HP
10
Mock elvárt viselkedésének beállítása
Egy mock objektum bármely függvénye bármilyen hívást enged, nem dob exceptiont, és default értéket ad vissza Setup által módosítható ez a működés Onnantól csak az így meghatározott hívások megengedettek! Egy mock objektum propertyje nem jegyzi meg az értékét, és default értéket ad vissza Setup/SetupAllProperties által módosítható ez a működés Mock<IEmployeeBusinessLogic> mbl = new Mock<IEmployeeBusinessLogic>(); // különféle elvárt viselkedések beállítása, paraméterektől függően mbl.Setup(m => m.CalcRemainingVacationDays(testEmployee)).Returns(99); mbl.Setup(m => m.CalcRemainingVacationDays(otherEmployee)).Returns(30); mbl.Setup(m => m.CalcRemainingVacationDays(It.IsAny<Employee>())).Returns(99); mbl.Setup(m => m.CalcRemainingVacationDays(null)).Throws<NullReferenceException>(); mbl.Setup(m => m.CalcRemainingVacationDays( It.Is<Employee>(emp => emp.Country == "Hungary"))).Returns(50); mbl.Setup(m => m.BaseVacationDays).Returns(6); // property fix érték mbl.Setup(m => m.BaseVacationDays); // property előkészítése használatra mbl.SetupAllProperties(); // összes property előkészítése ARRANGE fázisban csinálod ezt. A fenti Setup-ok egyszerre nyilván nem fognak működni, csak példák. Ha egyszer setupoltál, akkor csak a konkrétan megadott módokon tudod hívni a függvényt, különben exception!!! OE-NIK HP
11
Logika ellenőrzése mockkal (csak Setup után)
// ARRANGE Mock<IEmployeeBusinessLogic> mbl = new Mock<IEmployeeBusinessLogic>(); // ... Setup a később ellenőrzendő függvényekre, propertykre... // ACT ... // ASSERT // pont 3-szor hívódott, paraméter mindegy mbl.Verify(m => m.CalcRemainingVacationDays(It.IsAny<Employee>()), Times.Exactly(3)); // testEmployee paraméterrel max kétszer mbl.Verify(m => m.CalcRemainingVacationDays(testEmployee), Times.AtMost(2)); // otherEmployee-val egy hívás sem történt mbl.Verify(m => m.CalcRemainingVacationDays(otherEmployee), Times.Never); // property egyszer getelve lett mbl.VerifyGet(m => m.BaseVacationDays, Times.Once); // property egyszer 10-re lett setelve mbl.VerifySet(m => m.BaseVacationDays = 10, Times.Once); ASSERT fázisban csinálod ezt OE-NIK HP
12
Példa [Test] public void SelectedEmployeeChanged_RemainingDaysChanged() { // ARRANGE Mock<IEmployeeBusinessLogic> mbl = new Mock<IEmployeeBusinessLogic>(); mbl.Setup(m => m.CalcRemainingVacationDays(It.IsAny<Employee>())).Returns(99); MainWindowViewModel viewModel = new MainWindowViewModel(mbl.Object); // ACT viewModel.SelectedEmployee = new Employee(); // ASSERT // eredmény az elvárt: Assert.That(viewModel.RemainingVacationDays, Is.EqualTo(99)); // egyszer hívódott csak: mbl.Verify(m => m.CalcRemainingVacationDays(It.IsAny<Employee>()), Times.Once); } OE-NIK HP
Hasonló előadás
© 2024 SlidePlayer.hu Inc.
All rights reserved.