Top Banner
Building Unit Tests correctly with VS 2013
46

Building unit tests correctly with visual studio 2013

Aug 28, 2014

Download

Software

Dror Helper

Unit testing is now considered a mainstream practice, but that does not mean it is as common, pervasive or as well understood as it could or should be. Many programmers struggle with the quality of their tests and with the focus of their code. In this session we’ll learn how to write good unit testing code.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Building unit tests correctly with visual studio 2013

Building Unit Tests correctly with VS 2013

Page 2: Building unit tests correctly with visual studio 2013

About.ME

• Senior Consultant @CodeValue

• Developing software (Professionally) since 2002• Mocking code since 2008• Test driven professional

• Blogger: http://blog.drorhelper.com

Page 3: Building unit tests correctly with visual studio 2013

/* * You may think you know what the following code does. * But you dont. Trust me. * Fiddle with it, and youll spend many a sleepless * night cursing the moment you thought youd be clever * enough to "optimize" the code below. * Now close this file and go play with something else. */ //

// Dear maintainer:// // Once you are done trying to 'optimize' this routine,// and have realized what a terrible mistake that was,// please increment the following counter as a warning// to the next guy:// // total_hours_wasted_here = 42//

Page 4: Building unit tests correctly with visual studio 2013

//This code sucks, you know it and I know it. //Move on and call me an idiot later.

http://stackoverflow.com/questions/184618/what-is-the-best-comment-in-source-code-you-have-ever-encountered

We fear our code!

//Abandon all hope ye who enter beyond this point

//When I wrote this, only God and I understood what I was doing//Now, God only knows

// I dedicate all this code, all my work, to my wife, Darlene, who will // have to support me and our three children and the dog once it gets // released into the public.

//The following 1056 lines of code in this next method //is a line by line port from VB.NET to C#.//I ported this code but did not write the original code.//It remains to me a mystery as to what//the business logic is trying to accomplish here other than to serve as//some sort of a compensation shell game invented by a den of thieves.//Oh well, everyone wants this stuff to work the same as before.//I guess the devil you know is better than the devil you don't.

Page 5: Building unit tests correctly with visual studio 2013

“If we’re afraid to change the very thing we’ve created, we failed as professionals”Robert C. Martin

Page 6: Building unit tests correctly with visual studio 2013

Legacy code

Page 7: Building unit tests correctly with visual studio 2013

“Code without tests is bad code...

With tests, we can change the behavior of our code quickly and verifiably...”

Michael Feathers - “Working effectively with legacy code”

Page 8: Building unit tests correctly with visual studio 2013

This is a unit test

[Test]public void CheckPassword_ValidUser_ReturnTrue()

{bool result = CheckPassword(“user”,

“pass”);

Assert.That(result, Is.True);}

D

Page 9: Building unit tests correctly with visual studio 2013

This is also a unit test

[TestMethod]public void CheckPassword_ValidUser_ReturnTrue()

{bool result = CheckPassword(“user”,

“pass”);

Assert.IsTrue(result);}

D

Page 10: Building unit tests correctly with visual studio 2013

A unit test is…

1. Tests specific functionality

2. Clear pass/fail criteria

3. Good unit test runs in isolation

Page 11: Building unit tests correctly with visual studio 2013

Unit testing is an iterative effort

Unit testing is an iterative effort

Page 12: Building unit tests correctly with visual studio 2013

There’s more to unit tests then just “tests”

Written by the developer who wrote the code

Quick feedbackAvoid stupid bugsImmune to regressionChange your code without fearIn code documentation

Page 13: Building unit tests correctly with visual studio 2013

13 copyright 2008 trainologic LTD13

One last reasonYou’re already Testing your code – manually

So why not save the time?

Page 14: Building unit tests correctly with visual studio 2013

The cost of unit testing

IBM: Drivers MS: Windows MS: MSN MS: VS0%

20%40%60%80%

100%120%140%

120%135%

115%125%

Time taken to code a feature

WithoutTDD Using TDD

Page 15: Building unit tests correctly with visual studio 2013

The value of unit testing

IBM: Drivers MS: Windows MS: MSN MS: VS0%

20%40%60%80%

100%120%140%

61%

38%24%

9%

Using Test Driven Design

Time To Code Feature Defect density of team

Major quality improvement for minor time investment

Page 16: Building unit tests correctly with visual studio 2013

The cost of bugs

Requirements Coding Integration Testing Support0%

20%

40%

60%

80%

100%

010002000300040005000600070008000900010000

Where does it hurt?

% of Defects Introduced Cost to Fix a Defect

% d

efec

ts cr

eate

d

Thou

sand

$s

The pain is here! This is too late…

Page 17: Building unit tests correctly with visual studio 2013

Supporting environment

• The team

• Development environment

Page 18: Building unit tests correctly with visual studio 2013

The Team

• The team commitment is important• Learn from test reviews• Track results

Page 19: Building unit tests correctly with visual studio 2013

Tools of the trade

Server Dev Machine

Source Control

Build Server

Test Runner Code CoverageBuild Script

Unit Testing Framework

Isolation Framework

Page 20: Building unit tests correctly with visual studio 2013

Development environment

• Make it easy to write and run tests– Unit test framework– Test Runner– Isolation framework

• Know where you stand– Code coverage

Page 21: Building unit tests correctly with visual studio 2013

Unit testing frameworks

• Create test fixtures• Assert results• Additional utilities• Usually provide command-line/GUI runner

http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks

Page 22: Building unit tests correctly with visual studio 2013

[Test] public void AddTest() {

var cut = new Calculator(); var result = cut.Add(2, 3);

Assert.AreEqual(5, result); }

This is not a real unit test

Page 23: Building unit tests correctly with visual studio 2013

Real code has dependencies

Unit test

Code under test

Dependency Dependency

Page 24: Building unit tests correctly with visual studio 2013

The solution - Mocking

Fake object(s)

Unit test

Code under test

Dependency

Page 25: Building unit tests correctly with visual studio 2013

Isolation

• Replace production logic with custom logic

• We do this in order to – Focus the test on one class only– Test Interaction– Simplify Unit test writing

Page 26: Building unit tests correctly with visual studio 2013

What Mocking framework can do for you?

• Create Fake objects

• Set behavior on fake objects

• Verify method was called

• And more...

Page 27: Building unit tests correctly with visual studio 2013

[Test]public void IsLoginOK_LoggerThrowsException_CallsWebService(){ var fakeLogger = Isolate.Fake.Instance<ILogger>(); Isolate .WhenCalled(() => fakeLogger.Write("")) .WillThrow(new LoggerException()); var fakeWebService = Isolate.Fake.Instance<IWebService>();

var lm = new LoginManagerWithMockAndStub(fakeLogger,fakeWebService); lm.IsLoginOK("", "");

Isolate.Verify.WasCalledWithAnyArguments(() => fakeWebService.Write(""));}

Page 28: Building unit tests correctly with visual studio 2013

Open source

• FakeItEasy• Moq

• NMock3• nSubtitute

• Rhino Mocks

Free

•MS Fakes

Commercial

• Isolator•JustMoc

k

Page 29: Building unit tests correctly with visual studio 2013

Moq45%

Rhino Mocks23%

None9%

FakeItEasy6%

Nsubstitute6%

Isolator4%

Moles2%

MS Fakes2%

JustMocks2%

Other 1%

http://osherove.com/blog/2012/5/4/annual-poll-which-isolation-framework-do-you-use-if-any.html

Page 30: Building unit tests correctly with visual studio 2013

Code Coverage

So, What is a good code coverage?

Page 31: Building unit tests correctly with visual studio 2013

Source Control

Build Server

Commit

There you go

What’s new?

Build Agents

Start

working

Build ar

tifacts

We automatically get• Error reports &

logs• New version

installer• Help files• More…

Page 32: Building unit tests correctly with visual studio 2013

Build run at a Glance

Page 33: Building unit tests correctly with visual studio 2013

How I failed unit testing my codeUn

it tes

ti

ng is great!

Everyth

in

g s

hou

ld

b

e teste

d

I ca

n test “al

mo

st” everyt

hi

ng

Tests b

reak all t

he

ti

me

Unit

testi

ng

is

a

waste

of

ti

me

Page 34: Building unit tests correctly with visual studio 2013

A good unit test should be:

• Easy to understand• Trustworthy• Robust

Trust Your Tests!

Page 35: Building unit tests correctly with visual studio 2013

Trustworthy means deterministic

Problem• I cannot re-run the exact same test if a test fails

Solution• Don’t use Random in tests

– If you care about the values set them– If you don’t care about the values put defaults– Do not use Sleep & time related logic – fake it

• Use fake objects to “force” determinism into the test• When possible avoid threading in tests.

Page 36: Building unit tests correctly with visual studio 2013

Trustworthy also means not fragile

Ideally A test would only fail if a bug was introduced

ORRequirements changed

Page 37: Building unit tests correctly with visual studio 2013

How to avoid fragile tests

• Don’t test private/internal (most of the time)

• Fake as little as necessary

• Test only one thing (most of the time)

Fragile tests leads to anger. anger leads to hate. hate leads to suffering

Page 38: Building unit tests correctly with visual studio 2013

Readable unit tests

Unit test intent should be clear!

1.What is being tested?2.What is the desired outcome?3.Why did test fail?

Page 39: Building unit tests correctly with visual studio 2013

Learn to write “clean tests”

[Test] public void CalculatorSimpleTest() {

calc.ValidOperation = Calculator.Operation.Multiply; calc.ValidType = typeof (int); result = calc.Multiply(1, 3); Assert.IsTrue(result == 3); if (calc.ValidOperation == Calculator.Operation.Invalid) {

throw new Exception("Operation should be valid"); }

}

Page 40: Building unit tests correctly with visual studio 2013

Or suffer the consequences![Test] public void CalculatorSimpleTest() { var calc = new Calculator(); calc.ValidOperation = Calculator.Operation.Multiply; calc.ValidType = typeof (int); var result = calc.Multiply(-1, 3); Assert.AreEqual(result, -3); calc.ValidOperation = Calculator.Operation.Multiply; calc.ValidType = typeof (int); result = calc.Multiply(1, 3); Assert.IsTrue(result == 3); if (calc.ValidOperation == Calculator.Operation.Invalid) { throw new Exception("Operation should be valid"); } calc.ValidOperation = Calculator.Operation.Multiply; calc.ValidType = typeof (int); result = calc.Multiply(10, 3); Assert.AreEqual(result, 30); }

Page 41: Building unit tests correctly with visual studio 2013

Writing a good unit test

[Test] public void Multiply_PassTwoPositiveNumbers_ReturnCorrectResult() {

var calculator = CreateMultiplyCalculator();

var result = calculator.Multiply(1, 3);

Assert.AreEqual(result, 3); }

Assert

Act

Arrange

Page 42: Building unit tests correctly with visual studio 2013

So what about code reuse

Readability is more important than code reuse

• Create objects using factories• Put common and operations in helper

methods• Use inheritance – sparsely

Page 43: Building unit tests correctly with visual studio 2013

Avoid logic in the test (if, switch etc.)

Problem• Test is not readable• Has several possible paths• High maintain cost

Page 44: Building unit tests correctly with visual studio 2013

Tests should be deterministic

Solution• Split test to several tests – one for each

path– If logic change it’s easier to update some of the

tests (or delete them)• One Assert per test rule

Page 45: Building unit tests correctly with visual studio 2013

How to start with unit tests

1. Test what you’re working on – right now!

2. Write tests to reproduce reported bug

3. When refactoring existing code – use unit tests to make sure it still works.

4. Delete obsolete tests (and code)

5. All tests must run as part of CI build

Page 46: Building unit tests correctly with visual studio 2013