47
Advanced Object Oriented Design Unit Testing Principles S.O.L.I.D Refactoring

Unit Testing Full@

Embed Size (px)

Citation preview

Page 1: Unit Testing Full@

• Advanced Object Oriented Design• Unit Testing Principles• S.O.L.I.D• Refactoring

Page 2: Unit Testing Full@

Unit Testing Purpose

Proof that our classes work properly

If we repaired the bug in the code, we would like to be sure it won’t happen again

Isolate each part of the program and show that the individual parts are correct.

Page 3: Unit Testing Full@

Encourages programmers to make changes to the code since it is easy for the programmer to check if the piece is still working properly.

Unit testing allows the programmer to re-factor code and make sure the module still works correctly (i.e. regression testing).

Unit Testing Purpose

Page 4: Unit Testing Full@

If we did break something, we would like to know about it ASAP and not wait until QA finds the bug for us the sooner a bug is detected, the simpler and less costly it is to fix

If we break something we would like to know how it worked originally; unit testing provides a sort of "living document".

Unit Testing Purpose

Page 5: Unit Testing Full@

Enforce higher quality code because of SOLID, CLEAN code and OOP principles that is necessary for successful unit test creation.

This results in loosely coupled code, minimized dependencies in the system, etc.

Unit Testing Purpose

Page 6: Unit Testing Full@

Unit-testing will not catch every error in the program. It will not catch integration errors It will not catch performance problems It will not catch system-wide issues.

Disadvantages

Not all code may be covered with Unit Tests. For example if class has tight coupled instances

Page 7: Unit Testing Full@

Disadvantages

Aa a supplement to development, additional time required for implementation and support of unit test.

Page 8: Unit Testing Full@

Test Driven Development is not Unit Testing

Page 9: Unit Testing Full@

TDD Disadvantages

Big time investment, additional complexity, architecture impact, much more thinking ;)

Shallow (long) Learning Curve

Page 10: Unit Testing Full@

ReSharper

• Save time on compilation, locating & fixing errors – ReSharper instantly detects and highlights errors in your code and allows automatic corrections for most errors – much less possibilities for bugs

Example:

Page 11: Unit Testing Full@

ReSharper

• Automate routine tasks – Quickly create methods, properties, variables or classes from their usages, generate constructors, properties, delegating and equality members; implement and override members; and much more

Example:

Page 12: Unit Testing Full@

ReSharper

• Get useful hints right when you need them – IntelliSense, including code completion and quick parameter information

Example:

Page 13: Unit Testing Full@

ReSharper

• Improve your coding practices – Change is easy — with solution-wide, cross-language refactorings (nearly 6 times as many as in Microsoft Visual Studio, and growing), additional automated code transformations, and code cleanup Example:

Page 14: Unit Testing Full@

ReSharper

• Navigate to any corner of your solution – Reach any part of your code within seconds, with dozens of smart navigation and search features

Example:

Page 15: Unit Testing Full@

ReSharper

• Handle multi-language solutions with ease – Refactorings, navigation and search, and coding assistance work across C#, VB.NET, XAML, ASP.NET, TypeScript, JavaScript, CSS and more languages – Support all languages in the same solution – CSLP – TypeScript / HTML / C# / JavaScript

Example:

Page 16: Unit Testing Full@

ReSharper

• ReSharper provides a unit test runner that helps you run and debug unit tests based on NUnit, xUnit.net, MSTest, QUnit and Jasmine. You can explore tests, group them in different ways, break them down into individual sessions, see test output and navigate to source code from stack traces.

Page 17: Unit Testing Full@

ReSharper

• Analyzing code coverage with dotCover• You can easily discover the degree to which the

code of your solution is covered with unit tests.

Page 18: Unit Testing Full@

ReSharper

• For those who are working with Visual Studio Code have to use TSLint plugin to review, analyze code

• TSLint checks your TypeScript code for readability, maintainability, and functionality errors.

Example:

Page 19: Unit Testing Full@

Examples of when you should refactor the code before creating unit tests

Tested Method / Class (Unit) has more than one responsibility

Private Class / Methods. (Possible with using reflection, but will significantly reduce the performance of tests)

Method / Class don’t allow dependency injection, for example tightly coupled instances [new object();]

Page 20: Unit Testing Full@

All dependencies are explicitly passed in constructor/method parameters or properties. If it is not passed, it should not be used.

Must avoid hidden dependencies

Static methods (like DateTime.Now)

Singletons

Page 21: Unit Testing Full@

OOD, CLEAN Code and SOLID Principles

OOD principles we must use in order to get testable application Encapsulation

• Hide methods / properties…but REMEMBER private objects shouldn't be tested

Abstraction

• Domain analysis• Legacy analysis• Levels of abstraction

Inheritance

• Interfaces not concretes• Code reuse

Polymorphism

Page 22: Unit Testing Full@

S.O.L.I.D. - Five basic principles of object-oriented programming and design. The principles, when applied together, intend to make it more likely that a programmer will create a system that is easy to maintain and extend over time. The principles of SOLID are guidelines that can be applied while working on software to remove code smells by causing the programmer to refactor the software's source code until it is both legible and extensible.

Page 23: Unit Testing Full@

OOD, CLEAN Code and SOLID Principles

Single responsibility principle - a class should have only a single responsibility Makes clear the purpose of each class, increases maintainability, and promotes code reuse

Refactoring

Page 24: Unit Testing Full@

OOD, CLEAN Code and SOLID Principles

Open / closed principle – should be open for extension, but closed for modificationincreases the maintainability and reusability of code

If you will add new functionality, create a new class extending an existing one, rather than changing it

Refactoring

Page 25: Unit Testing Full@

OOD, CLEAN Code and SOLID Principles

Liskov substitution principle - objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program - It gives us Code reuse

If you create a new class extending an existing class, make sure it's completely interchangeable with its base

Page 26: Unit Testing Full@

OOD, CLEAN Code and SOLID Principles

Interface Segregation Principle

Refactoring

Page 27: Unit Testing Full@

OOD, CLEAN Code and SOLID Principles

Dependency Inversion Principle - Dependency Injection provides a means of injecting dependencies into an object as opposed to hard coding the dependencies within the object itself. Classes designed in this matter lend themselves to both unit testing via mocking or stubbing

Page 28: Unit Testing Full@

OOD, CLEAN Code and SOLID Principles

Design Patterns

Singleton

Factory

Builder

Object Pool

Command

Mediator

Observer

Strategy

Visitor

Adapter

Decorator

Proxy

Structural Behavioral Creational

Page 29: Unit Testing Full@

Unit Tests Code coverage

Unit Tests should cover upper and lower boundary conditions, including exceptions

Page 30: Unit Testing Full@

Unit Tests Code coverage

Page 31: Unit Testing Full@

Unit Tests Code coverage

Page 32: Unit Testing Full@

Exclude test projects from code coverage statistics

Unit Tests Code coverage

Why exclude non test projects

Page 33: Unit Testing Full@

Unit Tests

Creating Unit Tests (without depended objects, no mock objects needed)

Page 34: Unit Testing Full@

Unit Tests

Introducing Unit Tests with Mock objects

Page 35: Unit Testing Full@

Most of the unit tests requires using of MOCK objects. For example if you have provider to test and you don’t have connection any time you run the test or you don’t want to be depend on the connection. In order to create MOCK object we must use interface. We can create stub objects instead of mock – reduce performance, much more complicated and serves just for state not behaviour (cant return results)

Unit Tests with Mocks

Depend upon Abstractions. Do not depend upon concretions.

Page 36: Unit Testing Full@

Providing SUT with Mocking, Faking, Stubbing

Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.

Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).

Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls.

Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

Page 37: Unit Testing Full@

Providing SUT with Mocking, Faking, Stubbing

 Creating Mock Object

• The first step – create data on the mocking (properties, etc.)

• The second step - create expectations on the mock object. The expectations indicate which methods should be called on the mocks when the SUT is exercised.

Page 38: Unit Testing Full@

CODE UNIT TEST

Page 39: Unit Testing Full@

CODE UNIT TEST

Page 40: Unit Testing Full@

CODE UNIT TEST

Page 41: Unit Testing Full@

CODE UNIT TEST

Page 42: Unit Testing Full@

CODE UNIT TEST

Page 43: Unit Testing Full@

Mocking Objects https://github.com/Moq/moq4

Mocking is an integral part of unit testing. Although you can run your unit tests without use of mocking but it will drastically slow down the executing time of unit tests and also will be dependent on external resources.

The mock object knows in advance what is supposed to happen during the test (e.g. which of its methods calls will be invoked, etc.) and the mock object knows how it is supposed to react (e.g. what return value to provide). The mock will indicate whether what really happens differs from what is supposed to happen. A custom mock object could be coded for the expected behavior of each test case (see example)

In some cases we can use FAKE or STUB objects instead of Mock. For example concrete class don’t have an interface and we can’t mock this object. So we can create FAKE object and use it for testing. In this case we will dramatically reduce test performance and FAKE object has MUCH more less possibilities for testing.

Mock objects are simulated objects that mimic the behavior of real objects in controlled ways.

Page 44: Unit Testing Full@
Page 45: Unit Testing Full@

VS 2013 Code Coverage Tool

Page 46: Unit Testing Full@
Page 47: Unit Testing Full@

Example