SlideShare a Scribd company logo
1 of 46
The secret
Unit Testing tools
no one has ever told you about
Dror Helper | http://helpercode.com | @dhelper
Consultant & software architect
Developing software since 2002
Clean Coder & Test Driven Developer
Pluralsight author
https://www.pluralsight.com/authors/dror-helper
B: http://helpercode.com
T: @dhelper
About.ME
Why should you care about tools?
Background: unit testing tools
[Test]
public void AddItem_AddTwoValidProductsToCart_TotalEqualsItemsPrice()
{
var fakeRepository = A.Fake<IProductRepository>();
Product product1 = new Product(1, "product-1", 100);
Product product2 = new Product(2, "product-2", 200);
A.CallTo(() => fakeRepository.GetProductById(1)).Returns(product1));
A.CallTo(() => fakeRepository.GetProductById(2)).Returns(product2));
var shoppingCart = new ShoppingCart(fakeRepository);
shoppingCart.AddItem(1);
shoppingCart.AddItem(2);
Assert.That(shoppingCart.Total, Is.EqualTo(300));
}
@Test
public void addItem_addTwoValidProductsToCart_totalEqualsItemsPrice() {
IProductRepository fakeRepository = mock(IProductRepository.class);
Product product1 = new Product(1, "product-1", 100);
Product product2 = new Product(2, "product-2", 200);
when(fakeRepository.getProductById(1)).thenReturn(product1);
when(fakeRepository.getProductById(2)).thenReturn(product2);
ShoppingCart cart = new ShoppingCart(fakeRepository);
cart.AddItem(1);
cart.AddItem(2);
assertEquals(300.0, cart.getTotal(), 0);
}
TEST(ShoppingCartTests, AddProductById_AddTwoProducts_GetTotalPriceReturnSumPrice)
{
FakeRepository fake_repository;
Product product1 = Product(1, "product-1", 100);
Product product2 = Product(2, "product-2", 200);
EXPECT_CALL(fake_repository, GetProductById(1)).WillRepeatedly(Return(product1));
EXPECT_CALL(fake_repository, GetProductById(2)).WillRepeatedly(Return(product2));
ShoppingCart shopping_cart(fake_repository);
shopping_cart.AddProductById(1);
shopping_cart.AddProductById(2);
ASSERT_EQ(300, shopping_cart.GetTotalPrice());
}
(Most)
Unit Testing
Frameworks
[Test]
public void MyTest()
{
}
A good Unit Test should be:
Easy
to write
Simple
to read
Trivial
to maintain
What about AAA?
[Test]
public async void GetUserFromUrl() {
var clientFake = A.Fake<IJsonClient>();
A.CallTo(() => clientFake.HttpGetUncompressedAsync(A<string>.Ignored))
.Returns(Task.FromResult(JsonResult));
var userRepository = new UserRepository(clientFake);
var user = await userRepository.GetUser(11361);
var expected = new User {
Id=11361, DisplayName = "Dror Helper", ImageUrl=DefaultAvatar, Reputation=13904
};
Assert.That(user, Is.EqualTo(expected));
}
Arrange
 Act
 Assert
Test setup (Arrange)
Arrange issues
[TestMethod]
public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() {
var user1 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10};
var user2 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10};
var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 });
var viewModel = await InvokeAsync(() => new UserDetailsViewModel(fakeUserRepository));
await viewModel.LoadUser();
await viewModel.LoadUser();
var result = await InvokeAsync(() => ((SolidColorBrush)viewModel.ReputationTrend).Color);
Assert.AreEqual(Colors.White, result);
}
[TestInitialize]
public async Task InitializeViewModel() {
var user1 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10};
var user2 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10};
var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 });
_viewModel = await InvokeAsync(() => new UserDetailsViewModel(fakeUserRepository));
}
[TestMethod]
public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() {
await _viewModel.LoadUser();
await _viewModel.LoadUser();
var result = await InvokeAsync(() => ((SolidColorBrush)_viewModel.ReputationTrend).Color);
Assert.AreEqual(Colors.White, result);
}
Using Setup/TearDown
[TestInitialize]
public async Task InitializeViewModel() {
var user1 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10};
var user2 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10};
var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 });
_viewModel = await InvokeAsync(() => new UserDetailsViewModel(fakeUserRepository));
}
[TestMethod]
public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() {
await _viewModel.LoadUser();
await _viewModel.LoadUser();
var result = await InvokeAsync(() => ((SolidColorBrush)_viewModel.ReputationTrend).Color);
Assert.AreEqual(Colors.White, result);
}
private UserDetailsViewModel _viewModel;
Abusing Setup
methods
Extract to methods
[TestMethod]
public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() {
var user1 = CreateUser(10);
var user2 = CreateUser(10);
var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 });
var viewModel = await InvokeAsync(() => new UserDetailsViewModel(fakeUserRepository));
await viewModel.LoadUser();
await viewModel.LoadUser();
var result = await InvokeAsync(() => ((SolidColorBrush)viewModel.ReputationTrend).Color);
Assert.AreEqual(Colors.White, result);
}
Over abstraction
[TestMethod]
public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() {
var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 });
var viewModel = InitializeSystem(10, 10);
await RunTest(2);
CheckColor(Colors.White)
}
The problem with Factories
private User CreateUser(int reputation) {
return new User
{
ImageUrl = "http://dummy.jpg",
Reputation = reputation
};
}
private User CreateUser(int reputation, string imageUrl) {
return new User
{
ImageUrl = imageUrl,
Reputation = reputation
};
}
Solution: Builder Pattern
class UserBuilder {
private int _id, _reputation;
private string _name, _imageUrl;
public UserBuilder() {
_id = 1;
_name = "dummy";
_imageUrl = "http://dummy.jpg";
}
User Build() {
return new User {
Id = _id, Name = _name, ImageUrl = _imageUrl, Reputation = _reputation
};
}
}
Builder Pattern (cont)
class UserBuilder {
...
public UserBuilder WithName(string name) {
_name = name
return this;
}
public UserBuilder WithReputation(int reputation) {
_reputation = reputation
return this;
}
...
}
var user1 = new UserBuilder()
.WithReputation(10)
.Build();
Tool: AutoMocking Containers
Test Container SUT
http://blog.ploeh.dk/2013/03/11/auto-mocking-containe
New()
Configure
CreateCreate SUT
Act
Verification (Assert)
Can you spot the problem?
[TestMethod]
public void PerformSomeActionReturns42()
{
var myClass = ...
bool initOk = myClass.Initialize();
var result = myClass.PerformSomeAction();
Assert.IsTrue(initOk);
Assert.AreEqual(42, result);
}
How about now?
[TestMethod]
public void TestPasswordComplexity()
{
var result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "1!").Result;
Assert.IsFalse(result.Succeeded);
result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "123456789").Result;
Assert.IsFalse(result.Succeeded);
result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "123456789!").Result;
Assert.IsFalse(result.Succeeded);
result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "abcdefghijk").Result;
Assert.IsFalse(result.Succeeded);
result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "abcdefghijK1!").Result;
Assert.IsTrue(result.Succeeded);
}
http://stackoverflow.com/q/26400537/11361
How many Asserts per test?
One Assert per test
2 Asserts == 2 Tests
Really???
Multiple Asserts can make sense
[TestMethod]
public void CompareTwoAsserts()
{
var actual = GetNextMessage();
Assert.AreEqual(1, actual.Id);
Assert.AreEqual("str-1", actual.Content);
}
HOW UNIT TESTING FRAMEWORKS HURT YOUR UNIT TESTING EFFORTS
WHY TESTS THROW EXCEPTIONS ON FAILURE?
It’s trivial, and best practice
Helps Decouple test runner from test
But not necessary…
public class AssertAll
{
public static void Execute(params Action[] assertionsToRun)
{
var errorMessages = new List<exception>();
foreach (var action in assertionsToRun)
{
try
{
action.Invoke();
}
catch (Exception exc)
{
errorMessages.Add(exc);
}
}
if(errorMessages.Any())
{
string errorMessage = string.Join("n", errorMessages);
Assert.Fail($"The following conditions failed:n{errorMessage}"));
}
}
}
http://blog.drorhelper.com/2011/02/multiple-asserts-done-right.html
Using Assert.All
[TestMethod]
public void CompareTwoAsserts()
{
var actual = CreateMessage();
AssertAll.Execute(
() => Assert.AreEqual(1, actual.Id),
() => Assert.AreEqual("str-1", actual.Content);
}
Some frameworks are catching up!
https://github.com/nunit/docs/wiki/Multiple-Asserts
@Test
void dependentAssertions() {
assertAll("properties",
() -> {
String firstName = person.getFirstName();
assertNotNull(firstName);
// Executed only if the previous assertion is valid.
assertAll("first name",
() -> assertTrue(firstName.startsWith("J")),
() -> assertTrue(firstName.endsWith("n")));
},
() -> {
String lastName = person.getLastName();
assertNotNull(lastName);
// Executed only if the previous assertion is valid.
assertAll("last name",
() -> assertTrue(lastName.startsWith("D")),
() -> assertTrue(lastName.endsWith("e")));
});
}
Assert.AreEqual(5, 2 + 2); Assert.AreEqual(2 + 2, 5)
Assert.AreEqual(5, 2 + 2); Assert.IsTrue(2 + 2 == 5)
How to choose the right Assert?
• IsTrue vs. AreEqual
• Parameter ordering confusion
• StringAssert/CollectionAssert
It’s all about proper error messages
AssertHelper
[Test]
public void CompareTest()
{
var myClass = new MyClass();
Expect.That(() => myClass.ReturnFive() == 10);
}
[Test]
public void CompareTest()
{
var c1 = new[] { 1, 2, 3, 4, 5 }
Expect.That(() => c1.Contains(42);
}
https://github.com/dhelper/AssertHelper
Assertion Libraries: FluentAssertions
[Fact]
public void CompareTwoObjects()
{
var customer1 = new Customer("cust-1", "John Doe");
var customer2 = new Customer("cust-2", "John Doe");
customer1.ShouldBeEquivalentTo(customer2,
o => o.Excluding(customer => customer.Id));
}
http://www.fluentassertions.com/
Test organization
Test structure issues
• What to call the test?
• AAA is not mandatory
• What should I test?
• How to avoid unreadable, complicated tests?
- Unit testing framework provide no structure
The BDD approach
Step
Definitions
Specifications == focused test
Feature: Addition
In order to avoid silly mistakes
As a math idiot
I want to be told the sum of two numbers
Scenario: Add two numbers
Given I have entered 50 into the calculator
And I have entered 70 into the calculator
When I press add
Then the result should be 120 on the screen
BDD Example: SpecFlow
http://www.specflow.org/
[TestClass]
public class CardHasBeenDisabled {
private Card _card;
private Atm _subject;
void GivenTheCardIsDisabled() {
_card = new Card(false, 100);
_subject = new Atm(100);
}
void WhenTheAccountHolderRequestsMoney() {
_subject.RequestMoney(_card, 20);
}
void ThenTheAtmShouldRetainTheCard() {
Assert.IsTrue(_subject.CardIsRetained);
}
void AndTheAtmShouldSayTheCardHasBeenRetained() {
Assert.AreEqual(DisplayMessage.CardIsRetained, _subject.Message);
}
[TestMethod]
public void Execute()
{
this.BDDfy();
}
}
Tool: BDDfy
Test execution
Continuous Testing Tools
DotCover
Typemock
Runner
nCrunch
VS2017
(Enterprise)
The right tools will help you write good tests
Arrange
Builder
Pattern
AutoMocking
Containers
Assert
Multiple
Asserts
3rd party
Assertion
libraries
Test
Structure
“Classic” BDD
In-Code BDD
Continuous
Testing
Typemock Runner
DotCover
nCrunch
Live Unit Testing
Infinitest (Java)
Corvlet (.NET Core)
Thank you
@dhelper | http://helpercode.com

More Related Content

What's hot

Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...Naresha K
 
Deploying Straight to Production
Deploying Straight to ProductionDeploying Straight to Production
Deploying Straight to ProductionMark Baker
 
Presentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-railsPresentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-railsNovelys
 
Modernising Legacy Code
Modernising Legacy CodeModernising Legacy Code
Modernising Legacy CodeSamThePHPDev
 
jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginnersDivakar Gu
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Eyal Vardi
 
How to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI ComponentsHow to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI Componentscagataycivici
 
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019David Wengier
 
The Sky is Not Falling: Scaling Experimentation for Product Development
The Sky is Not Falling: Scaling Experimentation for Product DevelopmentThe Sky is Not Falling: Scaling Experimentation for Product Development
The Sky is Not Falling: Scaling Experimentation for Product DevelopmentOptimizely
 
Deep Dive into React Hooks
Deep Dive into React HooksDeep Dive into React Hooks
Deep Dive into React HooksFelix Kühl
 

What's hot (20)

Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
 
Graphql, REST and Apollo
Graphql, REST and ApolloGraphql, REST and Apollo
Graphql, REST and Apollo
 
Deploying Straight to Production
Deploying Straight to ProductionDeploying Straight to Production
Deploying Straight to Production
 
JS and patterns
JS and patternsJS and patterns
JS and patterns
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Presentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-railsPresentation technico-commercial-ruby-on-rails
Presentation technico-commercial-ruby-on-rails
 
guice-servlet
guice-servletguice-servlet
guice-servlet
 
Modernising Legacy Code
Modernising Legacy CodeModernising Legacy Code
Modernising Legacy Code
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
Nativescript angular
Nativescript angularNativescript angular
Nativescript angular
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
jQuery for beginners
jQuery for beginnersjQuery for beginners
jQuery for beginners
 
Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0Component lifecycle hooks in Angular 2.0
Component lifecycle hooks in Angular 2.0
 
How to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI ComponentsHow to Mess Up Your Angular UI Components
How to Mess Up Your Angular UI Components
 
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
 
Test doubles
Test doublesTest doubles
Test doubles
 
The Sky is Not Falling: Scaling Experimentation for Product Development
The Sky is Not Falling: Scaling Experimentation for Product DevelopmentThe Sky is Not Falling: Scaling Experimentation for Product Development
The Sky is Not Falling: Scaling Experimentation for Product Development
 
Developer Testing Tools Roundup
Developer Testing Tools RoundupDeveloper Testing Tools Roundup
Developer Testing Tools Roundup
 
Deep Dive into React Hooks
Deep Dive into React HooksDeep Dive into React Hooks
Deep Dive into React Hooks
 
Easy Button
Easy ButtonEasy Button
Easy Button
 

Similar to The secret unit testing tools no one has ever told you about

The secret unit testing tools no one ever told you about
The secret unit testing tools no one ever told you aboutThe secret unit testing tools no one ever told you about
The secret unit testing tools no one ever told you aboutDror Helper
 
Unit testing patterns for concurrent code
Unit testing patterns for concurrent codeUnit testing patterns for concurrent code
Unit testing patterns for concurrent codeDror Helper
 
How to write clean tests
How to write clean testsHow to write clean tests
How to write clean testsDanylenko Max
 
Тестирование и Django
Тестирование и DjangoТестирование и Django
Тестирование и DjangoMoscowDjango
 
Tech In Asia PDC 2017 - Best practice unit testing in mobile apps
Tech In Asia PDC 2017 - Best practice unit testing in mobile appsTech In Asia PDC 2017 - Best practice unit testing in mobile apps
Tech In Asia PDC 2017 - Best practice unit testing in mobile appsFandy Gotama
 
"Unit Testing for Mobile App" by Fandy Gotama (OLX Indonesia)
"Unit Testing for Mobile App" by Fandy Gotama  (OLX Indonesia)"Unit Testing for Mobile App" by Fandy Gotama  (OLX Indonesia)
"Unit Testing for Mobile App" by Fandy Gotama (OLX Indonesia)Tech in Asia ID
 
Secret unit testing tools
Secret unit testing toolsSecret unit testing tools
Secret unit testing toolsDror Helper
 
Testing with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs LifeTesting with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs LifePeter Gfader
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEnterprise PHP Center
 
Solit 2013, Автоматизация тестирования сложных систем: mixed mode automated t...
Solit 2013, Автоматизация тестирования сложных систем: mixed mode automated t...Solit 2013, Автоматизация тестирования сложных систем: mixed mode automated t...
Solit 2013, Автоматизация тестирования сложных систем: mixed mode automated t...solit
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good TestsTomek Kaczanowski
 
Bad test, good test
Bad test, good testBad test, good test
Bad test, good testSeb Rose
 
Testing ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NETTesting ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NETBen Hall
 
Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4jeresig
 

Similar to The secret unit testing tools no one has ever told you about (20)

The secret unit testing tools no one ever told you about
The secret unit testing tools no one ever told you aboutThe secret unit testing tools no one ever told you about
The secret unit testing tools no one ever told you about
 
Unit testing patterns for concurrent code
Unit testing patterns for concurrent codeUnit testing patterns for concurrent code
Unit testing patterns for concurrent code
 
How to write clean tests
How to write clean testsHow to write clean tests
How to write clean tests
 
Тестирование и Django
Тестирование и DjangoТестирование и Django
Тестирование и Django
 
Tech In Asia PDC 2017 - Best practice unit testing in mobile apps
Tech In Asia PDC 2017 - Best practice unit testing in mobile appsTech In Asia PDC 2017 - Best practice unit testing in mobile apps
Tech In Asia PDC 2017 - Best practice unit testing in mobile apps
 
"Unit Testing for Mobile App" by Fandy Gotama (OLX Indonesia)
"Unit Testing for Mobile App" by Fandy Gotama  (OLX Indonesia)"Unit Testing for Mobile App" by Fandy Gotama  (OLX Indonesia)
"Unit Testing for Mobile App" by Fandy Gotama (OLX Indonesia)
 
Secret unit testing tools
Secret unit testing toolsSecret unit testing tools
Secret unit testing tools
 
Testing with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs LifeTesting with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs Life
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
Clean tests good tests
Clean tests   good testsClean tests   good tests
Clean tests good tests
 
Good Practices On Test Automation
Good Practices On Test AutomationGood Practices On Test Automation
Good Practices On Test Automation
 
Solit 2013, Автоматизация тестирования сложных систем: mixed mode automated t...
Solit 2013, Автоматизация тестирования сложных систем: mixed mode automated t...Solit 2013, Автоматизация тестирования сложных систем: mixed mode automated t...
Solit 2013, Автоматизация тестирования сложных систем: mixed mode automated t...
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 
Bad test, good test
Bad test, good testBad test, good test
Bad test, good test
 
A Test of Strength
A Test of StrengthA Test of Strength
A Test of Strength
 
Unit testing with mock libs
Unit testing with mock libsUnit testing with mock libs
Unit testing with mock libs
 
PHP Unit Testing
PHP Unit TestingPHP Unit Testing
PHP Unit Testing
 
Testing ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NETTesting ASP.NET - Progressive.NET
Testing ASP.NET - Progressive.NET
 
Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4Testing, Performance Analysis, and jQuery 1.4
Testing, Performance Analysis, and jQuery 1.4
 

More from Dror Helper

Unit testing patterns for concurrent code
Unit testing patterns for concurrent codeUnit testing patterns for concurrent code
Unit testing patterns for concurrent codeDror Helper
 
Debugging with visual studio beyond 'F5'
Debugging with visual studio beyond 'F5'Debugging with visual studio beyond 'F5'
Debugging with visual studio beyond 'F5'Dror Helper
 
From clever code to better code
From clever code to better codeFrom clever code to better code
From clever code to better codeDror Helper
 
From clever code to better code
From clever code to better codeFrom clever code to better code
From clever code to better codeDror Helper
 
A software developer guide to working with aws
A software developer guide to working with awsA software developer guide to working with aws
A software developer guide to working with awsDror Helper
 
The role of the architect in agile
The role of the architect in agileThe role of the architect in agile
The role of the architect in agileDror Helper
 
Harnessing the power of aws using dot net core
Harnessing the power of aws using dot net coreHarnessing the power of aws using dot net core
Harnessing the power of aws using dot net coreDror Helper
 
Developing multi-platform microservices using .NET core
 Developing multi-platform microservices using .NET core Developing multi-platform microservices using .NET core
Developing multi-platform microservices using .NET coreDror Helper
 
Harnessing the power of aws using dot net
Harnessing the power of aws using dot netHarnessing the power of aws using dot net
Harnessing the power of aws using dot netDror Helper
 
C++ Unit testing - the good, the bad & the ugly
C++ Unit testing - the good, the bad & the uglyC++ Unit testing - the good, the bad & the ugly
C++ Unit testing - the good, the bad & the uglyDror Helper
 
Working with c++ legacy code
Working with c++ legacy codeWorking with c++ legacy code
Working with c++ legacy codeDror Helper
 
Visual Studio tricks every dot net developer should know
Visual Studio tricks every dot net developer should knowVisual Studio tricks every dot net developer should know
Visual Studio tricks every dot net developer should knowDror Helper
 
Electronics 101 for software developers
Electronics 101 for software developersElectronics 101 for software developers
Electronics 101 for software developersDror Helper
 
Navigating the xDD Alphabet Soup
Navigating the xDD Alphabet SoupNavigating the xDD Alphabet Soup
Navigating the xDD Alphabet SoupDror Helper
 
Building unit tests correctly
Building unit tests correctlyBuilding unit tests correctly
Building unit tests correctlyDror Helper
 
Who’s afraid of WinDbg
Who’s afraid of WinDbgWho’s afraid of WinDbg
Who’s afraid of WinDbgDror Helper
 
Designing with tests
Designing with testsDesigning with tests
Designing with testsDror Helper
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Dror Helper
 
Writing clean code in C# and .NET
Writing clean code in C# and .NETWriting clean code in C# and .NET
Writing clean code in C# and .NETDror Helper
 
Using FakeIteasy
Using FakeIteasyUsing FakeIteasy
Using FakeIteasyDror Helper
 

More from Dror Helper (20)

Unit testing patterns for concurrent code
Unit testing patterns for concurrent codeUnit testing patterns for concurrent code
Unit testing patterns for concurrent code
 
Debugging with visual studio beyond 'F5'
Debugging with visual studio beyond 'F5'Debugging with visual studio beyond 'F5'
Debugging with visual studio beyond 'F5'
 
From clever code to better code
From clever code to better codeFrom clever code to better code
From clever code to better code
 
From clever code to better code
From clever code to better codeFrom clever code to better code
From clever code to better code
 
A software developer guide to working with aws
A software developer guide to working with awsA software developer guide to working with aws
A software developer guide to working with aws
 
The role of the architect in agile
The role of the architect in agileThe role of the architect in agile
The role of the architect in agile
 
Harnessing the power of aws using dot net core
Harnessing the power of aws using dot net coreHarnessing the power of aws using dot net core
Harnessing the power of aws using dot net core
 
Developing multi-platform microservices using .NET core
 Developing multi-platform microservices using .NET core Developing multi-platform microservices using .NET core
Developing multi-platform microservices using .NET core
 
Harnessing the power of aws using dot net
Harnessing the power of aws using dot netHarnessing the power of aws using dot net
Harnessing the power of aws using dot net
 
C++ Unit testing - the good, the bad & the ugly
C++ Unit testing - the good, the bad & the uglyC++ Unit testing - the good, the bad & the ugly
C++ Unit testing - the good, the bad & the ugly
 
Working with c++ legacy code
Working with c++ legacy codeWorking with c++ legacy code
Working with c++ legacy code
 
Visual Studio tricks every dot net developer should know
Visual Studio tricks every dot net developer should knowVisual Studio tricks every dot net developer should know
Visual Studio tricks every dot net developer should know
 
Electronics 101 for software developers
Electronics 101 for software developersElectronics 101 for software developers
Electronics 101 for software developers
 
Navigating the xDD Alphabet Soup
Navigating the xDD Alphabet SoupNavigating the xDD Alphabet Soup
Navigating the xDD Alphabet Soup
 
Building unit tests correctly
Building unit tests correctlyBuilding unit tests correctly
Building unit tests correctly
 
Who’s afraid of WinDbg
Who’s afraid of WinDbgWho’s afraid of WinDbg
Who’s afraid of WinDbg
 
Designing with tests
Designing with testsDesigning with tests
Designing with tests
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013
 
Writing clean code in C# and .NET
Writing clean code in C# and .NETWriting clean code in C# and .NET
Writing clean code in C# and .NET
 
Using FakeIteasy
Using FakeIteasyUsing FakeIteasy
Using FakeIteasy
 

Recently uploaded

Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 

Recently uploaded (20)

Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 

The secret unit testing tools no one has ever told you about

  • 1. The secret Unit Testing tools no one has ever told you about Dror Helper | http://helpercode.com | @dhelper
  • 2. Consultant & software architect Developing software since 2002 Clean Coder & Test Driven Developer Pluralsight author https://www.pluralsight.com/authors/dror-helper B: http://helpercode.com T: @dhelper About.ME
  • 3. Why should you care about tools?
  • 5. [Test] public void AddItem_AddTwoValidProductsToCart_TotalEqualsItemsPrice() { var fakeRepository = A.Fake<IProductRepository>(); Product product1 = new Product(1, "product-1", 100); Product product2 = new Product(2, "product-2", 200); A.CallTo(() => fakeRepository.GetProductById(1)).Returns(product1)); A.CallTo(() => fakeRepository.GetProductById(2)).Returns(product2)); var shoppingCart = new ShoppingCart(fakeRepository); shoppingCart.AddItem(1); shoppingCart.AddItem(2); Assert.That(shoppingCart.Total, Is.EqualTo(300)); }
  • 6. @Test public void addItem_addTwoValidProductsToCart_totalEqualsItemsPrice() { IProductRepository fakeRepository = mock(IProductRepository.class); Product product1 = new Product(1, "product-1", 100); Product product2 = new Product(2, "product-2", 200); when(fakeRepository.getProductById(1)).thenReturn(product1); when(fakeRepository.getProductById(2)).thenReturn(product2); ShoppingCart cart = new ShoppingCart(fakeRepository); cart.AddItem(1); cart.AddItem(2); assertEquals(300.0, cart.getTotal(), 0); }
  • 7. TEST(ShoppingCartTests, AddProductById_AddTwoProducts_GetTotalPriceReturnSumPrice) { FakeRepository fake_repository; Product product1 = Product(1, "product-1", 100); Product product2 = Product(2, "product-2", 200); EXPECT_CALL(fake_repository, GetProductById(1)).WillRepeatedly(Return(product1)); EXPECT_CALL(fake_repository, GetProductById(2)).WillRepeatedly(Return(product2)); ShoppingCart shopping_cart(fake_repository); shopping_cart.AddProductById(1); shopping_cart.AddProductById(2); ASSERT_EQ(300, shopping_cart.GetTotalPrice()); }
  • 9. A good Unit Test should be: Easy to write Simple to read Trivial to maintain
  • 10. What about AAA? [Test] public async void GetUserFromUrl() { var clientFake = A.Fake<IJsonClient>(); A.CallTo(() => clientFake.HttpGetUncompressedAsync(A<string>.Ignored)) .Returns(Task.FromResult(JsonResult)); var userRepository = new UserRepository(clientFake); var user = await userRepository.GetUser(11361); var expected = new User { Id=11361, DisplayName = "Dror Helper", ImageUrl=DefaultAvatar, Reputation=13904 }; Assert.That(user, Is.EqualTo(expected)); } Arrange  Act  Assert
  • 12. Arrange issues [TestMethod] public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() { var user1 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10}; var user2 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10}; var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 }); var viewModel = await InvokeAsync(() => new UserDetailsViewModel(fakeUserRepository)); await viewModel.LoadUser(); await viewModel.LoadUser(); var result = await InvokeAsync(() => ((SolidColorBrush)viewModel.ReputationTrend).Color); Assert.AreEqual(Colors.White, result); }
  • 13. [TestInitialize] public async Task InitializeViewModel() { var user1 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10}; var user2 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10}; var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 }); _viewModel = await InvokeAsync(() => new UserDetailsViewModel(fakeUserRepository)); } [TestMethod] public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() { await _viewModel.LoadUser(); await _viewModel.LoadUser(); var result = await InvokeAsync(() => ((SolidColorBrush)_viewModel.ReputationTrend).Color); Assert.AreEqual(Colors.White, result); } Using Setup/TearDown
  • 14. [TestInitialize] public async Task InitializeViewModel() { var user1 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10}; var user2 = new User {ImageUrl = "http://dummy.jpg", Reputation = 10}; var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 }); _viewModel = await InvokeAsync(() => new UserDetailsViewModel(fakeUserRepository)); } [TestMethod] public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() { await _viewModel.LoadUser(); await _viewModel.LoadUser(); var result = await InvokeAsync(() => ((SolidColorBrush)_viewModel.ReputationTrend).Color); Assert.AreEqual(Colors.White, result); } private UserDetailsViewModel _viewModel;
  • 16. Extract to methods [TestMethod] public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() { var user1 = CreateUser(10); var user2 = CreateUser(10); var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 }); var viewModel = await InvokeAsync(() => new UserDetailsViewModel(fakeUserRepository)); await viewModel.LoadUser(); await viewModel.LoadUser(); var result = await InvokeAsync(() => ((SolidColorBrush)viewModel.ReputationTrend).Color); Assert.AreEqual(Colors.White, result); }
  • 17. Over abstraction [TestMethod] public async Task LoadUser_ReputationStaysTheSame_ReputationTrendSame() { var fakeUserRepository = new FakeUserRepository(new[] { user1, user2 }); var viewModel = InitializeSystem(10, 10); await RunTest(2); CheckColor(Colors.White) }
  • 18. The problem with Factories private User CreateUser(int reputation) { return new User { ImageUrl = "http://dummy.jpg", Reputation = reputation }; } private User CreateUser(int reputation, string imageUrl) { return new User { ImageUrl = imageUrl, Reputation = reputation }; }
  • 19. Solution: Builder Pattern class UserBuilder { private int _id, _reputation; private string _name, _imageUrl; public UserBuilder() { _id = 1; _name = "dummy"; _imageUrl = "http://dummy.jpg"; } User Build() { return new User { Id = _id, Name = _name, ImageUrl = _imageUrl, Reputation = _reputation }; } }
  • 20. Builder Pattern (cont) class UserBuilder { ... public UserBuilder WithName(string name) { _name = name return this; } public UserBuilder WithReputation(int reputation) { _reputation = reputation return this; } ... } var user1 = new UserBuilder() .WithReputation(10) .Build();
  • 21. Tool: AutoMocking Containers Test Container SUT http://blog.ploeh.dk/2013/03/11/auto-mocking-containe New() Configure CreateCreate SUT Act
  • 23. Can you spot the problem? [TestMethod] public void PerformSomeActionReturns42() { var myClass = ... bool initOk = myClass.Initialize(); var result = myClass.PerformSomeAction(); Assert.IsTrue(initOk); Assert.AreEqual(42, result); }
  • 24. How about now? [TestMethod] public void TestPasswordComplexity() { var result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "1!").Result; Assert.IsFalse(result.Succeeded); result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "123456789").Result; Assert.IsFalse(result.Succeeded); result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "123456789!").Result; Assert.IsFalse(result.Succeeded); result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "abcdefghijk").Result; Assert.IsFalse(result.Succeeded); result = _UserManager.ChangePasswordAsync(_TestUser.Id, "Password123!", "abcdefghijK1!").Result; Assert.IsTrue(result.Succeeded); } http://stackoverflow.com/q/26400537/11361
  • 25. How many Asserts per test? One Assert per test 2 Asserts == 2 Tests Really???
  • 26. Multiple Asserts can make sense [TestMethod] public void CompareTwoAsserts() { var actual = GetNextMessage(); Assert.AreEqual(1, actual.Id); Assert.AreEqual("str-1", actual.Content); }
  • 27. HOW UNIT TESTING FRAMEWORKS HURT YOUR UNIT TESTING EFFORTS WHY TESTS THROW EXCEPTIONS ON FAILURE? It’s trivial, and best practice Helps Decouple test runner from test But not necessary…
  • 28. public class AssertAll { public static void Execute(params Action[] assertionsToRun) { var errorMessages = new List<exception>(); foreach (var action in assertionsToRun) { try { action.Invoke(); } catch (Exception exc) { errorMessages.Add(exc); } } if(errorMessages.Any()) { string errorMessage = string.Join("n", errorMessages); Assert.Fail($"The following conditions failed:n{errorMessage}")); } } } http://blog.drorhelper.com/2011/02/multiple-asserts-done-right.html
  • 29. Using Assert.All [TestMethod] public void CompareTwoAsserts() { var actual = CreateMessage(); AssertAll.Execute( () => Assert.AreEqual(1, actual.Id), () => Assert.AreEqual("str-1", actual.Content); }
  • 30. Some frameworks are catching up! https://github.com/nunit/docs/wiki/Multiple-Asserts
  • 31. @Test void dependentAssertions() { assertAll("properties", () -> { String firstName = person.getFirstName(); assertNotNull(firstName); // Executed only if the previous assertion is valid. assertAll("first name", () -> assertTrue(firstName.startsWith("J")), () -> assertTrue(firstName.endsWith("n"))); }, () -> { String lastName = person.getLastName(); assertNotNull(lastName); // Executed only if the previous assertion is valid. assertAll("last name", () -> assertTrue(lastName.startsWith("D")), () -> assertTrue(lastName.endsWith("e"))); }); }
  • 32. Assert.AreEqual(5, 2 + 2); Assert.AreEqual(2 + 2, 5)
  • 33. Assert.AreEqual(5, 2 + 2); Assert.IsTrue(2 + 2 == 5)
  • 34. How to choose the right Assert? • IsTrue vs. AreEqual • Parameter ordering confusion • StringAssert/CollectionAssert It’s all about proper error messages
  • 35. AssertHelper [Test] public void CompareTest() { var myClass = new MyClass(); Expect.That(() => myClass.ReturnFive() == 10); } [Test] public void CompareTest() { var c1 = new[] { 1, 2, 3, 4, 5 } Expect.That(() => c1.Contains(42); } https://github.com/dhelper/AssertHelper
  • 36. Assertion Libraries: FluentAssertions [Fact] public void CompareTwoObjects() { var customer1 = new Customer("cust-1", "John Doe"); var customer2 = new Customer("cust-2", "John Doe"); customer1.ShouldBeEquivalentTo(customer2, o => o.Excluding(customer => customer.Id)); } http://www.fluentassertions.com/
  • 38. Test structure issues • What to call the test? • AAA is not mandatory • What should I test? • How to avoid unreadable, complicated tests? - Unit testing framework provide no structure
  • 40. Specifications == focused test Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario: Add two numbers Given I have entered 50 into the calculator And I have entered 70 into the calculator When I press add Then the result should be 120 on the screen
  • 42. [TestClass] public class CardHasBeenDisabled { private Card _card; private Atm _subject; void GivenTheCardIsDisabled() { _card = new Card(false, 100); _subject = new Atm(100); } void WhenTheAccountHolderRequestsMoney() { _subject.RequestMoney(_card, 20); } void ThenTheAtmShouldRetainTheCard() { Assert.IsTrue(_subject.CardIsRetained); } void AndTheAtmShouldSayTheCardHasBeenRetained() { Assert.AreEqual(DisplayMessage.CardIsRetained, _subject.Message); } [TestMethod] public void Execute() { this.BDDfy(); } } Tool: BDDfy
  • 45. The right tools will help you write good tests Arrange Builder Pattern AutoMocking Containers Assert Multiple Asserts 3rd party Assertion libraries Test Structure “Classic” BDD In-Code BDD Continuous Testing Typemock Runner DotCover nCrunch Live Unit Testing Infinitest (Java) Corvlet (.NET Core)
  • 46. Thank you @dhelper | http://helpercode.com

Editor's Notes

  1. Let’s talk about why you should care about tools. The reason I want to talk to you about unit testing tools is that In the beginning of my career I have failed miserably with unit tests, , more than once. Each time I was sure I’ve finally got it and each time I’ve ended up deleting all of my tests. Today I know that the reason I’ve failed was not because I was a bad developer but because I lacked proper guidance. Luckily for me I had the pleasure to work with several individuals who taught me how to write good unit tests but there is no reason you should need tt. Unit testing is not a rocket science all you need is someone to guide you in the right direction. and with the right tools will provide guidance and help you write good unit tests.
  2. SHOW DEMO!
  3. - Two asserts – no idea what caused the failure Test is testing several things Left or right? InstanceOf MSTest vs. NUnit
  4. Organized Overhead
  5. Organized Overhead