Unit Testing and Mocking

Slides:



Advertisements
Similar presentations
Introduction to Unit Testing Svetlin Nakov Telerik Corporation
Advertisements

What is Unit Testing? How TDD Works? Tsvyatko Konov Telerik Corporation
Unit testing C# classes “If it isn’t tested it doesn’t work” Unit testing C# classes1.
Unit Testing & Defensive Programming. F-22 Raptor Fighter.
Software Quality Assurance QA Engineering, Testing, Bug Tracking, Test Automation Software University Technical Trainers SoftUni Team.
AngularJS Services Built-in and Custom Services SoftUni Team Technical Trainers Software University
Methods Writing and using methods, overloads, ref, out SoftUni Team Technical Trainers Software University
Testing Web Services Unit Testing, Data Layer Testing, Web API Controllers Testing, Integration Testing Web Services & Cloud SoftUni Team testing Technical.
Fundamentals SoftUni Welcome to Software University SoftUni Team Technical Trainers Software University
Code Correctness, Readability, Maintainability Telerik Software Academy Telerik School.
Advanced JavaScript Course Introduction SoftUni Team Technical Trainers Software University
Project Tracking Tools Trello, Asana, Basecamp, GitHub Issue Tracker, TRAC SoftUni Team Technical Trainers Software University
Building Rock-Solid Software Nikolay Kostov Telerik Software Academy academy.telerik.com Senior Software Developer and Technical Trainer
Software Testing Lifecycle Exit Criteria Evaluation, Continuous Integration Ivan Yonkov Technical Trainer Software University.
Design Patterns: Structural Design Patterns
High-Quality Programming Code Code Correctness, Readability, Maintainability, Testability, Etc. SoftUni Team Technical Trainers Software University
JavaScript Design Patterns Private Fields, Module, Revealing Module, Revealing Prototype, … Software University Technical Trainers SoftUni.
Conditional Statements Implementing Control-Flow Logic in C# SoftUni Team Technical Trainers Software University
Consuming REST Services from C# SoftUni Team Technical Trainers Software University
Loops Repeating Code Multiple Times SoftUni Team Technical Trainers Software University
Entity Framework Performance SoftUni Team Technical Trainers Software University
Microsoft Azure SoftUni Team Technical Trainers Software University
Svetlin Nakov Technical Trainer Software University
Build Processes and Continuous Integration Automating Build Processes Software University Technical Trainers SoftUni Team.
Unit Testing Building Rock-Solid Software SoftUni Team Technical Trainers Software University
SOLID Principles in Software Design
Project Tracking Tools Trello, Asana, Basecamp, GitHub Issue Tracker, TRAC Angel Georgiev Part-time Trainer Software University
Test-Driven Development Learn the "Test First" Approach to Coding SoftUni Team Technical Trainers Software University
Defining Classes Classes, Fields, Constructors, Methods, Properties SoftUni Team Technical Trainers Software University
Functions Reusable Parts of Code SoftUni Team Technical Trainers Software University
Static Members and Namespaces Static Members, Indexers, Operators, Namespaces SoftUni Team Technical Trainers Software University
Controllers and Markup Controllers, $scope, Markup, Directives, Expressions, Binding, Filters, Validation SoftUni Team Technical Trainers Software University.
Asynchronous Web Services Writing Asynchronous Web Services SoftUni Team Technical Trainers Software University
Defensive Programming, Assertions and Exceptions Designing Error Steady Code SoftUni Team Technical Trainers Software University
JavaScript Modules and Patterns Private Fields, Module, Revealing Module, Revealing Prototype, … Software University Technical Trainers.
Responsive Design Design that Adapts to Different Devices SoftUni Team Technical Trainers Software University
Unit Testing in JavaScript with Mocha, Chai and Karma SoftUni Team Technical Trainers Software University
Unit Testing Building Rock-Solid Software Svetlin Nakov Technical Trainer Software University
High-Quality Programming Code Code Correctness, Readability, Maintainability Svetlin Nakov Technical Trainer Software University
High-Quality Code: Course Introduction Course Introduction SoftUni Team Technical Trainers Software University
Design Patterns: Structural Design Patterns General and reusable solutions to common problems in software design Software University
SOLID Principles in Software Design
Advanced C# Course Introduction SoftUni Team Technical Trainers Software University
Prototype Chain and Inheritance Prototype chain, Inheritance, Accessing Base Members Software University Technical Trainers SoftUni Team.
Reflection Programming under the hood SoftUni Team Technical Trainers Software University
Mocking with Moq Tools for Easier Unit Testing SoftUni Team Technical Trainers Software University
Mocking Unit Testing Methods with External Dependencies SoftUni Team Technical Trainers Software University
Mocking with Moq Mocking tools for easier unit testing Svetlin Nakov Technical Trainer Software University
Test-Driven Development Learn the "Test First" Approach to Coding Svetlin Nakov Technical Trainer Software University
Sets, Dictionaries SoftUni Team Technical Trainers Software University
Northwest Arkansas.Net User Group Jay Smith Tyson Foods, Inc. Unit Testing nUnit, nUnitAsp, nUnitForms.
High-Quality Code: Course Introduction Course Introduction SoftUni Team Technical Trainers Software University
Functional Programming Data Aggregation and Nested Queries Ivan Yonkov Technical Trainer Software University
Doctrine The PHP ORM SoftUni Team Technical Trainers Software University
Inheritance Class Hierarchies SoftUni Team Technical Trainers Software University
Stacks and Queues Processing Sequences of Elements SoftUni Team Technical Trainers Software University
Generics SoftUni Team Technical Trainers Software University
High-Quality Programming Code Code Correctness, Readability, Maintainability, Testability, Etc. SoftUni Team Technical Trainers Software University
Interface Segregation / Dependency Inversion
Services & Dependency Injection
Building Rock-Solid Software
Mocking tools for easier unit testing
Mocking Tool for easier unit testing
Unit Testing with Mocha
Introduction to Unit Testing in JavaScript
Best practices and architecture
Software Quality Assurance
Building Rock-Solid Software
Unit testing C# classes
Component Testing (Unit Testing)
Presentation transcript:

Unit Testing and Mocking Writing Unit Tests, Dependency Injection, Mocking Web Services & Cloud SoftUni Team Technical Trainers Software University http://softuni.bg © Software University Foundation – http://softuni.org This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

Table of Contents Unit Testing Dependency Injection Mocking What is it? Unit testing Frameworks Visual Studio Team Test Unit Testing Best Practices Dependency Injection Mocking Using Moq

What is Unit Testing?

* Unit Test – Definition A unit test is a piece of code written by a developer that exercises a very small, specific area of functionality of the code being tested. “Program testing can be used to show the presence of bugs but never to show their absence!” Edsger Dijkstra, [1972]

Manual Testing You have already done unit testing Manually, by hand Manual tests are less efficient Not structured Not repeatable Not on all your code Not easy to do as it should be

Unit Test – Example int Sum(int[] array) { int sum = 0; for (int i = 0; i < array.Length; i++) sum += array[i]; return sum; } void TestSum() if (Sum(new int[] { 1, 2 }) != 3) throw new TestFailedException("1+2 != 3"); if (Sum(new int[] { -2 }) != -2) throw new TestFailedException("-2 != -2"); if (Sum(new int[] { }) != 0) throw new TestFailedException("0 != 0");

Unit Testing – Some Facts Tests are specific pieces of code In most cases unit tests are written by developers, not by QA engineers Unit tests are released into the code repository (TFS / SVN / Git) along with the code they test Unit testing framework is needed Visual Studio Team Test (VSTT) NUnit, XUnit, Gallio, etc.

Unit Testing – More Facts All classes should be tested All methods should be tested Trivial code may be omitted E.g. property getters and setters Private methods can be omitted Ideally all unit tests should pass before committing in the source control repository

Why Unit Tests? Unit tests dramatically decrease the number of defects in the code Unit tests improve design Unit tests are good documentation Unit tests reduce the cost of change Unit tests allow refactoring Unit tests decrease the defect-injection rate due to refactoring / changes

Unit Testing Frameworks * Unit Testing Frameworks

Unit Testing Frameworks JUnit The first popular unit testing framework Based on Java, written by Kent Beck & Co. Similar frameworks have been developed for a broad range of computer languages NUnit, XUnit – for C# and all .NET languages cppUnit, jsUnit, PhpUnit, PerlUnit, ... Visual Studio Team Test (VSTT) Developed by Microsoft, integrated in VS

Visual Studio Team Test (VSTT) * Visual Studio Team Test (VSTT)

Visual Studio Team Test – Features Team Test (VSTT) is very well integrated with Visual Studio Create test projects and unit tests Execute unit tests View execution results View code coverage Located in the assembly Microsoft.VisualStudio.QualityTools. UnitTestFramework.dll

Visual Studio Team Test – Attributes Test code is annotated using custom attributes: [TestClass] – denotes a class holding unit tests [TestMethod] – denotes a unit test method (test case) [ExpectedException] – declares that the test should cause an exception [Timeout] – sets a timeout for test execution [Ignore] – temporary ignored test case [ClassInitialize], [ClassCleanup] – setup / cleanup logic for the testing class [TestInitialize], [TestCleanup] – setup / cleanup logic for each test case

Assertions Predicate is a true / false statement Assertion is a predicate placed in a program code (check for some condition) Developers expect the predicate is always true at that place If an assertion fails, the method call does not return and an error is reported Example of VSTT assertion: Assert.AreEqual(expectedValue, actualValue, "Error message.");

VSTT – Assertions Assertions check a condition Throw a TestFailedException if the condition is not satisfied Comparing values for equality Comparing objects (by reference) Checking for null value AreEqual(expectedValue, actualValue [, message]) AreSame(expectedObject, actualObject [, message]) IsNull(object [, message]) IsNotNull(object [, message])

VSTT – Assertions (2) Checking conditions Forced test failure IsTrue(condition [, message]) IsFalse(condition [, message]) Fail([message])

The 3A Pattern Arrange all necessary preconditions and inputs Act on the object or method under test Assert that the expected results have occurred [TestMethod] public void TestDeposit() { BankAccount account = new BankAccount(); account.Deposit(125.0); account.Deposit(25.0); Assert.AreEqual(150.0, account.Balance, "Balance is wrong."); } The 3А Pattern

Code Coverage Code coverage 70-80% coverage is excellent Shows what percent of the code we've covered High code coverage means less untested code We may have pointless unit tests that are calculated in the code coverage 70-80% coverage is excellent

VSTT – Example public class Account { private decimal balance; public decimal Balance { … } public void Deposit(decimal amount) this.balance += amount; } public void Withdraw(decimal amount) this.balance -= amount; public void TransferFunds(Account destination, decimal amount)

VSTT – Example (2) using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] public class AccountTest { [TestMethod] public void TestTransferFunds() Account source = new Account(); source.Deposit(200.00M); Account dest = new Account(); dest.Deposit(150.00M); source.TransferFunds(dest, 100.00M); Assert.AreEqual(250.00M, dest.Balance); Assert.AreEqual(100.00M, source.Balance); }

VSTT – Screenshot

Visual Studio Team Test Live Demo

Unit Testing Best Practices * Unit Testing Best Practices

Naming Standards for Unit Tests The test name should express a specific requirement that is tested Usually [TestMethod_StateUnderTest_ExpectedBehavior] E.g. TestAccountDepositNegativeSum() or AccountShouldNotDepositNegativeSum() The test name should include Expected input or state Expected result output or state Name of the tested method or class

Naming Standards for Unit Tests – Example Given the method: with requirement to ignore numbers greater than 100 in the summing process The test name could be: public int Sum(params int[] values) TestSumNumberIgnoredIfGreaterThan100

When Should a Test be Changed or Removed? Generally, a passing test should never be removed These tests make sure that code changes don't break working code A passing test should only be changed to make it more readable When tests don't pass, it usually means there are conflicting requirements

When Should a Test be Changed or Removed? (2) Example: New features allow negative numbers [ExpectedException(typeof(Exception), "Negatives not allowed")] void TestSum_FirstNegativeNumberThrowsException() { Sum (-1, 1, 2); }

When Should a Test be Changed or Removed? (3) New developer writes the following test: Earlier test fails due to a requirement change void TestSum_FirstNegativeNumberCalculatesCorrectly() { int sumResult = sum(-1, 1, 2); Assert.AreEqual(2, sumResult); }

When Should a Test be Changed or Removed? (4) Two courses of action: Delete (or make obsolete) the failing test after verifying it is invalid Change the old test: Either testing the new requirement Or test the older requirement under new settings

Tests Should Reflect Required Reality What's wrong with the following test? A failing test should prove that there is something wrong with the production code Not with the unit test code int Sum(int a, int b) –> returns sum of a and b public void Sum_AddsOneAndTwo() { int result = Sum(1, 2); Assert.AreEqual(4, result, "Bad sum"); }

What Should Assert Messages Say? Assert message in a test could be one of the most important things Tells us what we expected to happen but didn't and what happened instead Good assert message helps us track bugs and understand unit tests more easily Example: "Withdrawal failed: accounts are not supposed to have negative balance."

What Should Assert Messages Say? (2) Express what should have happened and what did not happen “Verify() did not throw any exception” “Connect() did not open the connection before returning it” Do not: Provide empty or meaningless messages Provide messages that repeat the name of the test case

Avoid Multiple Asserts in a Single Unit Test Avoid multiple asserts in a single test case If the first assert fails, the test execution stops for this test case Affect future coders to add assertions to test rather than introducing a new one void TestSum_AnyParamBiggerThan1000IsNotSummed() { Assert.AreEqual(3, Sum(1001, 1, 2); Assert.AreEqual(3, Sum(1, 1001, 2); Assert.AreEqual(3, Sum(1, 2, 1001); }

Unit Testing – The Challenge The concept of unit testing has been around the developer community for many years New methodologies in particular Scrum and XP, have turned unit testing into a cardinal foundation of software development Writing good & effective unit tests is hard! This is where supporting integrated tools and suggested guidelines enter the picture The are tools for auto-generating unit tests (e.g. Pex) The developer still needs to adjust the generated code

Summary Write testable code Follow the 3A pattern Write unit tests according to specifications When specifications change, the tests should change too When writing unit tests, follow the rules of high-quality code Good naming, cohesion and coupling, code reuse, etc. Unit tests can serve as documentation for your code

Dependency Inversion Principle

DIP – Dependency Inversion Principle "Dependency Inversion Principle says that high-level modules should not depend on low-level modules. Both should depend on abstractions." "Abstractions should not depend on details. Details should depend on abstractions." Agile Principles, Patterns, and Practices in C# Goal: decoupling between modules through abstractions Programming through interfaces

Dependencies in Traditional Programming High level modules use lower lever modules E.g. UI depends on the Business Layer Business layer depends on Infrastructure, database, utilities External libraries Static methods (Façade for example) Classes are instantiated everywhere

DI: Depend on Abstractions How it should be? Classes should declare what they need Constructors should require dependencies Dependencies should be abstractions How to do it Dependency Injection (DI) The Hollywood principle "Don't call us, we'll call you!"

Depend on Abstractions Depend on abstractions means to work through interfaces instead directly use dependent classes

Dependency Inversion Principle: How? Constructor injection Dependencies are passed through constructors Pros Classes self-documenting requirements Works well without container Always valid state Cons Many parameters Some methods may not need everything

Constructor Injection – Example public class Copy { private IReader reader; private IWriter writer; public Copy(IReader reader, IWriter writer) this.reader = reader; this.writer = writer; } // Read / write data through the reader / writer var copy = new Copy(new ConsoleReader(), new FileWriter("out.txt"));

Dependency Inversion Principle: How? (2) Property injection Dependencies are passed through setters Pros Can be changed anytime Very flexible Cons Possible invalid state of the object Less intuitive

Property Injection – Example public class Copy { public IReader Reader { get; set; } public IWriter Writer { get; set; } public void CopyAllChars(reader, writer) // Read / write data through the reader / writer } Copy copy = new Copy(); copy.Reader = new ConsoleReader(); copy.Writer = new FileWriter("output.txt"); copy.CopyAllChars();

Dependency Inversion Principle: How? (3) Parameter injection Dependencies are passed through method parameters Pros No change in rest of the class Very flexible Cons Many parameters Breaks the method signature

Parameter Injection – Example public class Copy { public CopyAllChars(IReader reader, IWriter writer) // Read / write data through the reader / writer } Copy copy = new Copy(); var reader = new ConsoleReader(); var writer = new FileWriter("output.txt"); copy.CopyAllChars(reader, writer);

Dependency Inversion Principle: Violations Classic violations of DIP Using of the new keyword Using static methods / properties How to fix broken DIP? Extract interfaces + use constructor injection Inversion of Control (IoC) container

Inversion of Control and Dependency Injection A library / framework calls your code and injects context Inversion of control container (IoC) Several ways to take dependencies when programming through interfaces (dependency injection) Constructor injection Property injection / interface injection Parameter injection

Inversion of Control Containers (IoC) IoC containers Responsible for object instantiation Map interfaces to classes E.g. maps IReader to ConsoleReader Classes initiated at application start-up Interfaces are registered into the container Dependencies on interfaces are injected at runtime Examples – StructureMap, Ninject, Spring Framework and more

Dependency Inversion Principle Live Demo

Mocking

How to Write Testable Code Inversion of Control Pattern There is a decoupling of the execution of a certain task from implementation Every module can focus on what it is designed for Modules make no assumptions about what other systems do but rely on their contracts Replacing modules has no side effect on other modules More info at http://en.wikipedia.org/wiki/Inversion_of_control

Testing Data-Driven Applications ExtractImageUrls cannot be reliably tested Accessing external data can return different results public class Crawler { public IEnumerable<string> ExtractImageUrls( string pageUrl) var client = new WebClient(); var html = client.DownloadString(pageUrl); return this.ParseImages(html); } private IEnumerable<string> ParseImages( string html) { ... } Dependency

How to Test a Unit with a Dependency? Extract said dependency in an interface Class should receive the interface through dependency injection Create a mock of the dependency with static behavior (i.e. always returning same data) Pass mock object to the tested class Assert if tested class behavior is correct

Testing a Unit with Dependencies Create dependency interface Create a class and implement the interface public interface IHtmlProvider { string DownloadHtml(string pageUrl); } public class HtmlProvider : IHtmlProvider { public string DownloadHtml(string pageUrl) var client = new WebClient(); return client.DownloadString(pageUrl); } Extract login into the class

Testing a Unit with Dependencies (2) Work through interface in tested class public class Crawler { public Crawler(IHtmlProvider htmlProvider) this.HtmlProvider = htmlProvider; } public IHtmlProvider HtmlProvider { get; set; } public IEnumerable<string> ExtractImageUrls(string pageUrl) var html = this.HtmlProvider.DownloadHtml(pageUrl); return this.ParseImages(html); Dependency Injection through constructor

Testing a Unit with Dependencies (3) In the tests project, set up a mock object using Moq Fake IHtmlProvider whose DownloadHtml() method always returns the same string public class HtmlProviderMock { public HtmlProviderMock this.Setup(); } public IHtmlProvider HtmlProvider { get; set; } private void Setup() var mock = new Mock<IHtmlProvider>(); mock.Setup(p => p.DownloadHtml(It.IsAny<string>())) .Returns("<html>...</html>"); this.HtmlProvider = mock.Object;

Testing a Unit with Dependencies (4) Pass the mock object in the tests to the test class constructor [TestMethod] public void ExtractImageUrls_Should_Return_Collection_Of_Page_Image_Urls() { var mock = new HtmlProviderMock(); var crawler = new Crawler(mock.HtmlProvider); var imageUrls = this.crawler.ExtractImageUrls(string.Empty) .OrderBy(url => url).ToList(); var expectedResults = new [] { "nakov.png", "courses/inner/background.jpeg" }; CollectionAssert.AreEqual(expectedResults, imageUrls); }

Mocking Live Demo

Unit Testing and Mocking https://softuni.bg/courses/web-services-and-cloud/ © Software University Foundation – http://softuni.org This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

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 "Web Services and Cloud" course by Telerik Academy under CC-BY-NC-SA license © Software University Foundation – http://softuni.org This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.

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