Presentation is loading. Please wait.

Presentation is loading. Please wait.

Building Rock-Solid Software

Similar presentations


Presentation on theme: "Building Rock-Solid Software"— Presentation transcript:

1 Building Rock-Solid Software
Unit Testing Building Rock-Solid Software C# OOP Advanced SoftUni Team Technical Trainers Software University

2 Table of Contents What is Unit Testing? Unit Testing Basics
* Table of Contents What is Unit Testing? Unit Testing Basics 3A Pattern Good Practices Unit Testing Frameworks – NUnit Mocking and Mock Objects (c) 2007 National Academy for Software Development - All rights reserved. Unauthorized copying or re-distribution is strictly prohibited.*

3 sli.do #CSharp-OOP Questions
© Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

4 Seven Testing Principles
© Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

5 Seven Testing Principles
Testing is context dependent Testing is done differently in different contexts Example: safety-critical software is tested differently from an e- commerce site

6 Seven Testing Principles (2)
Exhaustive testing is impossible All combinations of inputs and preconditions are usually almost infinite number Testing everything is not feasible Except for trivial cases Risk analysis and priorities should be used to focus testing efforts

7 Seven Testing Principles (3)
Early testing is always prefered Testing activities shall be started as early as possible And shall be focused on defined objectives The later a bug is found – the more it costs!

8 Seven Testing Principles (4)
Defect clustering Testing effort shall be focused proportionally To the expected and later observed defect density of modules A small number of modules usually contains most of the defects discovered Responsible for most of the operational failures In your opinion which operation is most likely to cause your Operation system to fail? - Opening Microsoft Word - Open IE - Opening 10 different application all at the same time

9 Seven Testing Principles (5)
Pesticide paradox Same tests repeated over and over again tend to loose their effectiveness Previously undetected defects remain undiscovered New and modified test cases should be developed

10 Seven Testing Principles (6)
Testing shows presence of defects Testing can show that defects are present Cannot prove that there are no defects Appropriate testing reduces the probability for defects

11 Seven Testing Principles (7)
Absence-of-errors fallacy Finding and fixing defects itself does not help in these cases: The system built is unusable Does not fulfill the users’ needs and expectations

12 Software Used to Test Software
What is Unit Testing Software Used to Test Software

13 Manual Testing Not structured Not repeatable
Can’t cover all of the code Not as easy to do as it should be void testSum() { if (this.sum(1, 2) != 3) { throw new Exception("1 + 2 != 3"); }

14 Manual Testing (2) Bonus: We need a structured approach that:
Allows refactoring Reduces the cost of change Decreases the number of defects in the code Bonus: Improves design © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

15 Automated Testing System System tests Integration tests Unit tests
The whole system System A single module Integration Unit A single class © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

16 NUnit 3.0 Setup and First Test

17 NUnit Initially ported from Junit
NUnit version 3.0, has been completely rewritten NUnit is Open Source software Support for a wide range of .NET platforms

18 Nunit vs MSTest NUnit allows for parameterized tests
Readable Assert method NUnit has frequent version updates MS-Test has only one per VS version. Expected exception message assertion Can be done using attribute in NUnit Must be done using Try-Catch in MS-Test

19 Problem: NUnit Test Add NUnit 3.0 extension to Visual Studio
Create console application project Add BankAcount class Create NUnit Project Write test against BankAcount

20 Solution: NUnit Test Add NUnit 3.0 Adapter Add NUnit Template
Show Test Explorer

21 Solution: NUnit Test (2)
Write your first test [TestFixture] public class BankAcountTests { [Test] public void AcountInitializeWithPositiveValue() BankAcount acount = new BankAcount(2000m); Assert.AreEqual(2000m, acount.Amount); } Class attributes mean this is a class with tests Test Method Assert class come with NUnit

22 What is AAA Testing Pattern
Organize and clarify test code by breaking down a test case into the following functional sections: The Arrange section of a unit test initializes objects and sets the value of the data that is passed to the test case The Act section invokes the test case with the arranged parameters The Assert section verifies the test case behaves as expected

23 Each test should test a single behavior!
3A Pattern [Test] public void DepositShouldAddMoney() { BankAccount account = new BankAccount(); account.Deposit(50); Assert.assertTrue(account.Balance == 50) } Each test should test a single behavior! © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

24 Problem: Test Axe Load provided solution in Visual Studio
Add new project Tests Create a class AxeTests Create the following tests: Test if weapon loses durability after attack Test attacking with a broken weapon © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

25 Solution: Test Axe [Test] public void AxeLosesDurabilyAfterAttack() {
// Arrange Axe axe = new Axe(10, 10); Dummy dummy = new Dummy(10, 10); // Act axe.Attack(dummy); // Assert Assert.AreEqual(9, axe.DurabilityPoints); }

26 Solution: Test Axe (2) [Test] public void BrokenAxeCantAttack() {
Axe axe = new Axe(1, 1); Dummy dummy = new Dummy(10, 10); axe.Attack(dummy); var ex = Assert.Throws<InvalidOperationException> (() => axe.Attack(dummy)); Assert.That(ex.Message, Is.EqualTo("Axe is broken.")); }

27 Problem: Test Dummy Create a class DummyTests
Create the following tests Dummy loses health if attacked Dead Dummy throws exception if attacked Dead Dummy can give XP Alive Dummy can't give XP

28 There is a better solution…
Solution: Test Dummy [Test] public void DummyLosesHealthAfterAttack() { // Arrange Dummy dummy = new Dummy(20, 10); // Act dummy.TakeAttack(5); // Assert Assert.IsTrue(dummy.Health == 15); } // TODO: Write the rest of the tests There is a better solution…

29 Unit Testing Best Practices
How to Write Good Tests

30 Asserts Condition Asserts Comparison Asserts Exception Asserts
Assert.IsTrue(bool condition, string message); Assert.AreEqual(expected value, actual value); Assert.Throws( Type expectedExceptionType, TestDelegate code);

31 Asserts (2) String Assert Collection Assert File Assert
StringAssert.Contains (string expected, string actual); CollectionAssert.Contains (IEnumerable expected, object actual); FileAssert.AreEqual (FileInfo expected, FileInfo actual);

32 IsTrue() vs AreEqual()
IsTrue(condition) AreEqual(expected, actual) Assert.IsTrue(axe.DurabilityPoints == 12); Assert.AreEqual(12, axe.DurabilityPoints); Better description when expecting value © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

33 Helps finding the problem
Assertion Messages Assertions can show messages Helps with diagnostics Hamcrest is useful tool for test diagnostics Assert.AreEqual(12, axe.DurabilityPoints, "Axe Durability doesn't change after attack"); Helps finding the problem © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

34 Magic Numbers Avoid using magic numbers
private const int axeDurability = 10; private const int axeAttack = 10; [Test] public void AxeLosesDurabilyAfterAttack() { Axe axe = new Axe(axeDurability, axeAttack); Assert.AreEqual(axeDurability, axe.DurabilityPoints, "…"); } © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

35 Don't Repeat Yourself private BankAccount account; [SetUp]
public void TestInit() { this.account = new BankAccount(); } [TearDown] public void TestCleanUp() {} Executes before each test Executes after each test © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

36 Naming Test Methods Test names Should use business domain terminology
Should be descriptive and readable IncrementNumber() {} Test1() {} TestTransfer() {} DepositAddsMoneyToBalance() {} DepositNegativeShouldNotAddMoney() {} TransferSubtractsFromSourceAddsToDestAccount() {} © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

37 Problem: Refactor Tests
Refactor the tests for Axe and Dummy classes Make sure that Names of test methods are descriptive You use appropriate assertions (assert equals vs assert true) You use assertion messages There are no magic numbers There is no code duplication (Don’t Repeat Yourself)

38 Solution: Refactor Tests
private const int AxeAttack = 2; private const int AxeDurability = 2; private const int DummyHealth = 20; private const int DummyXP = 20; private Axe axe; private Dummy dummy; [SetUp] public void TestInit() { this.axe = new Axe(AxeAttack, AxeDurability); this.dummy = new Dummy(DummyHealth, DummyXP); }

39 Solution: Refactor Tests (2)
public void AxeLosesDurabilyAfterAttack() { axe.Attack(dummy); Assert.AreEqual(1, axe.DurabilityPoints, "Axe Durability doesn't change after attack"); } public void BrokenAxeCantAttack() var ex = Assert.Throws<InvalidOperationException>( () => axe.Attack(dummy)); Assert.That(ex.Message, Is.EqualTo("Axe is broken."));

40 Live Exercises in Class (Lab)
Unit Testing Basics Live Exercises in Class (Lab)

41 Dependencies Isolating Behaviors

42 Coupling and Testing Consider testing the following code:
We want to test a single behavior Concrete Implementation public class Bank { private AccountManager accountManager; public Bank() { this. accountManager = new AccountManager(); } public AccountInfo getInfo(String id) { … } Bank depends on AccountManager © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

43 Coupling and Testing (2)
Need to find solution to decouple classes Interface Bank AccountManager +Account GetAccount() uses Bank inherits bugs Bank AccountManager © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

44 Dependency Injection Decouples classes and makes code testable
Using Interface public interface IAccountManager { Account Account { get; } } public class Bank { private IAccountManager accountManager; public Bank(IAccountManager accountManager) { this.accountManager = accountManager; Independent from Implementation Injecting dependencies © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

45 Goal: Isolating Test Behavior
In other words, to fixate all moving parts [Test] public void TestGetInfoById() { AccountManager manager = new AccountManager() public Account Account(String id) { … } } Bank bank = new Bank(manager); AccountInfo info = bank.getInfo(id); // Assert… Anonymous class Fake interface implementation with fixed behavior © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

46 Problem: Fake Axe and Dummy
Test if hero gains XP when target dies To do this, first: Make Hero class testable (use Dependency Injection) Introduce Interfaces for Axe and Dummy Interface IWeapon Interface ITarget Create test using a fake Weapon and fake Dummy

47 Solution: Fake Axe and Dummy
public interface IWeapon { void Attack(Target target); int AttackPoints { get; } int DurabilityPoints { get; } } public interface ITarget { void TakeAttack(int attackPoints); int Health { get; } int GiveExperience(); bool IsDead(); }

48 Solution: Fake Axe and Dummy (2)
// Hero: Dependency Injection through constructor public Hero(String name, IWeapon weapon) { this.name = name; this.experience = 0; this.weapon = weapon; } public class Axe : IWeapon { public void attack(ITarget target) { … } }

49 Solution: Fake Axe and Dummy (3)
public class FakeTarget : ITarget { public void TakeAttack(int attackPoints) } public int Health => 0; public int GiveExperience() { return 20; } public bool IsDead() { return true; } // TODO: Implement FakeWeapon

50 Solution: Fake Axe and Dummy (4)
private const string HeroName = "Pesho" [Test] public void HeroGainsExperienceAfterAttackIfTargetDies() { ITarget fakeTarget = new FakeTarget() IWeapon fakeWeapon = new FakeWeapon() Hero hero = new Hero(HeroName, fakeWeapon); hero.attack(fakeTarget); // Assert… }

51 Not suitable for big interfaces
Fake Implementations Not readable, cumbersome and boilerplate [Test] public void TestRequiresFakeImplementationOfBigInterface() { // Arrange Database db = new BankDatabase() { // Too many methods… } AccountManager manager = new AccountManager(db); // Act… // Assert… Not suitable for big interfaces © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

52 Mocking Mock objects simulate behavior of real objects
The object supplies non-deterministic results - Time It has states that are difficult to create or reproduce - Network It is slow - Database It does not yet exist or may change behavior; It would have to include information and methods exclusively for testing purposes (and not for its actual task). © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

53 Moq Moq provides us with an easy way of creating mock objects
Simple to use Strongly typed Minimalistic Mock<IContainer> mockContainer = new Mock<IContainer>(); Mock<ICustomerView> mockView = new Mock<ICustomerView>(); Moq Moq (pronounced "Mock You") is an open-source mocking framework Facilitates the mocking process by providing an API for creating fake objects (mocks) No need to create fake classes for every possible test scenario Can mock almost any type, not just interfaces E.g. Random, DateTime, etc. © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

54 Mocking Example Mock<ITarget> fakeTarget = new Mock<ITarget>(); fakeTarget .Setup(p => p.TakeAttack(It.IsAny<int>())) .Callback(() => hero.Weapon.DurabilityPoints -= 1); .Setup(p => p.Health) .Returns(0); © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

55 Problem: Mocking Include Moq in the project
Mock fakes from previous problem Test if hero gains XP when target dies

56 Solution: Mocking [Test]
public void HeroGainsExperienceAfterAttackIfTargetDies() { Mock<ITarget> fakeTarget = new Mock<ITarget>(); fakeTarget.Setup(p => p.Health).Returns(0); fakeTarget.Setup(p => p.GiveExperience()).Returns(20); fakeTarget.Setup(p => p.IsDead()).Returns(true); Mock<IWeapon> fakeWeapon = new Mock<IWeapon>(); Hero hero = new Hero("Pesho", fakeWeapon.Object); hero.Attack(fakeTarget.Object); Assert.AreEqual(20, hero.Experience); }

57 Summary Unit Testing helps us build solid code
* Summary Unit Testing helps us build solid code Structure your unit tests – 3A Pattern Use descriptive names for your tests Use different assertions depending on the situation Dependency Injection makes your classes testable Looses coupling and improves design Mock objects to isolate tested behavior (c) 2007 National Academy for Software Development - All rights reserved. Unauthorized copying or re-distribution is strictly prohibited.*

58 Enumerations and Annotations
© Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

59 License This course (slides, examples, demos, videos, homework, etc.) is licensed under the "Creative Commons Attribution- NonCommercial-ShareAlike 4.0 International" license Attribution: this work may contain portions from "Fundamentals of Computer Programming with Java" book by Svetlin Nakov & Co. under CC-BY-SA license "C# Part I" course by Telerik Academy under CC-BY-NC-SA license "C# Part II" course by Telerik Academy under CC-BY-NC-SA license © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

60 Free Trainings @ Software University
Software University Foundation – softuni.org Software University – High-Quality Education, Profession and Job for Software Developers softuni.bg Software Facebook facebook.com/SoftwareUniversity Software YouTube youtube.com/SoftwareUniversity Software University Forums – forum.softuni.bg © Software University Foundation – This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.


Download ppt "Building Rock-Solid Software"

Similar presentations


Ads by Google