SlideShare a Scribd company logo
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

PPTX
Secret unit testing tools no one ever told you about
Dror Helper
 
PDF
Redux for ReactJS Programmers
David Rodenas
 
PDF
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
Guy Royse
 
PDF
Spring 2.5
Paul Bakker
 
PPTX
Typed? Dynamic? Both! Cross-platform DSLs in C#
Vagif Abilov
 
PPTX
Meet Magento Belarus debug Pavel Novitsky (eng)
Pavel Novitsky
 
PPTX
EVERYTHING ABOUT STATIC CODE ANALYSIS FOR A JAVA PROGRAMMER
Andrey Karpov
 
PDF
Advanced java practical semester 6_computer science
Niraj Bharambe
 
Secret unit testing tools no one ever told you about
Dror Helper
 
Redux for ReactJS Programmers
David Rodenas
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
Guy Royse
 
Spring 2.5
Paul Bakker
 
Typed? Dynamic? Both! Cross-platform DSLs in C#
Vagif Abilov
 
Meet Magento Belarus debug Pavel Novitsky (eng)
Pavel Novitsky
 
EVERYTHING ABOUT STATIC CODE ANALYSIS FOR A JAVA PROGRAMMER
Andrey Karpov
 
Advanced java practical semester 6_computer science
Niraj Bharambe
 

What's hot (20)

PDF
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Naresha K
 
PDF
Graphql, REST and Apollo
Christoffer Noring
 
PPTX
Deploying Straight to Production
Mark Baker
 
PDF
JS and patterns
David Rodenas
 
KEY
SOLID Principles
Chris Weldon
 
PDF
Presentation technico-commercial-ruby-on-rails
Novelys
 
PDF
guice-servlet
Masaaki Yonebayashi
 
ODP
Modernising Legacy Code
SamThePHPDev
 
PPT
Test driven development_for_php
Lean Teams Consultancy
 
PDF
Nativescript angular
Christoffer Noring
 
KEY
Unit testing zend framework apps
Michelangelo van Dam
 
PPT
jQuery for beginners
Divakar Gu
 
PPTX
Component lifecycle hooks in Angular 2.0
Eyal Vardi
 
PDF
How to Mess Up Your Angular UI Components
cagataycivici
 
PPTX
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
David Wengier
 
PDF
Test doubles
Francisco Iglesias Gómez
 
PDF
The Sky is Not Falling: Scaling Experimentation for Product Development
Optimizely
 
PDF
Developer Testing Tools Roundup
John Ferguson Smart Limited
 
PDF
Deep Dive into React Hooks
Felix Kühl
 
RTF
Easy Button
Adam Dale
 
Effective Java with Groovy & Kotlin How Languages Influence Adoption of Good ...
Naresha K
 
Graphql, REST and Apollo
Christoffer Noring
 
Deploying Straight to Production
Mark Baker
 
JS and patterns
David Rodenas
 
SOLID Principles
Chris Weldon
 
Presentation technico-commercial-ruby-on-rails
Novelys
 
guice-servlet
Masaaki Yonebayashi
 
Modernising Legacy Code
SamThePHPDev
 
Test driven development_for_php
Lean Teams Consultancy
 
Nativescript angular
Christoffer Noring
 
Unit testing zend framework apps
Michelangelo van Dam
 
jQuery for beginners
Divakar Gu
 
Component lifecycle hooks in Angular 2.0
Eyal Vardi
 
How to Mess Up Your Angular UI Components
cagataycivici
 
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
David Wengier
 
The Sky is Not Falling: Scaling Experimentation for Product Development
Optimizely
 
Developer Testing Tools Roundup
John Ferguson Smart Limited
 
Deep Dive into React Hooks
Felix Kühl
 
Easy Button
Adam Dale
 
Ad

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

PPTX
The secret unit testing tools no one ever told you about
Dror Helper
 
PPTX
Secret unit testing tools
Dror Helper
 
PPTX
Building unit tests correctly
Dror Helper
 
PPTX
Building unit tests correctly with visual studio 2013
Dror Helper
 
PPTX
Tdd & unit test
GomathiNayagam S
 
PDF
Unit testing (workshop)
Foyzul Karim
 
PPTX
Practical unit testing tips
Typemock
 
PPT
Using xUnit as a Swiss-Aarmy Testing Toolkit
Chris Oldwood
 
PPTX
Rc2010 tdd
JasonOffutt
 
PDF
Breaking Dependencies to Allow Unit Testing
Steven Smith
 
PDF
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014
FalafelSoftware
 
PPTX
Breaking Dependencies to Allow Unit Testing
Steven Smith
 
PPTX
Type mock isolator
MaslowB
 
PPTX
Writing Good Tests
Matteo Baglini
 
PDF
Unit testing - 9 design hints
Victor Rentea
 
PPTX
Refactoring Away from Test Hell
Alastair Smith
 
PPTX
Unit tests = maintenance hell ?
Thibaud Desodt
 
PPTX
Introduction to Software Testing
Sergio Arroyo
 
PDF
ITB 2023 10 Techniques for writing easy yet stupidly thorough unit tests_Dan ...
Ortus Solutions, Corp
 
PPTX
Principles and patterns for test driven development
Stephen Fuqua
 
The secret unit testing tools no one ever told you about
Dror Helper
 
Secret unit testing tools
Dror Helper
 
Building unit tests correctly
Dror Helper
 
Building unit tests correctly with visual studio 2013
Dror Helper
 
Tdd & unit test
GomathiNayagam S
 
Unit testing (workshop)
Foyzul Karim
 
Practical unit testing tips
Typemock
 
Using xUnit as a Swiss-Aarmy Testing Toolkit
Chris Oldwood
 
Rc2010 tdd
JasonOffutt
 
Breaking Dependencies to Allow Unit Testing
Steven Smith
 
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014
FalafelSoftware
 
Breaking Dependencies to Allow Unit Testing
Steven Smith
 
Type mock isolator
MaslowB
 
Writing Good Tests
Matteo Baglini
 
Unit testing - 9 design hints
Victor Rentea
 
Refactoring Away from Test Hell
Alastair Smith
 
Unit tests = maintenance hell ?
Thibaud Desodt
 
Introduction to Software Testing
Sergio Arroyo
 
ITB 2023 10 Techniques for writing easy yet stupidly thorough unit tests_Dan ...
Ortus Solutions, Corp
 
Principles and patterns for test driven development
Stephen Fuqua
 
Ad

More from Dror Helper (20)

PPTX
Unit testing patterns for concurrent code
Dror Helper
 
PPTX
Debugging with visual studio beyond 'F5'
Dror Helper
 
PPTX
From clever code to better code
Dror Helper
 
PPTX
From clever code to better code
Dror Helper
 
PPTX
A software developer guide to working with aws
Dror Helper
 
PPTX
The role of the architect in agile
Dror Helper
 
PDF
Harnessing the power of aws using dot net core
Dror Helper
 
PPTX
Developing multi-platform microservices using .NET core
Dror Helper
 
PPTX
Harnessing the power of aws using dot net
Dror Helper
 
PPTX
C++ Unit testing - the good, the bad & the ugly
Dror Helper
 
PPTX
Working with c++ legacy code
Dror Helper
 
PPTX
Visual Studio tricks every dot net developer should know
Dror Helper
 
PPTX
Electronics 101 for software developers
Dror Helper
 
PPTX
Navigating the xDD Alphabet Soup
Dror Helper
 
PPTX
Who’s afraid of WinDbg
Dror Helper
 
PPTX
Unit testing patterns for concurrent code
Dror Helper
 
PPTX
Designing with tests
Dror Helper
 
PPTX
Writing clean code in C# and .NET
Dror Helper
 
PPTX
Using FakeIteasy
Dror Helper
 
PPTX
Battle of The Mocking Frameworks
Dror Helper
 
Unit testing patterns for concurrent code
Dror Helper
 
Debugging with visual studio beyond 'F5'
Dror Helper
 
From clever code to better code
Dror Helper
 
From clever code to better code
Dror Helper
 
A software developer guide to working with aws
Dror Helper
 
The role of the architect in agile
Dror Helper
 
Harnessing the power of aws using dot net core
Dror Helper
 
Developing multi-platform microservices using .NET core
Dror Helper
 
Harnessing the power of aws using dot net
Dror Helper
 
C++ Unit testing - the good, the bad & the ugly
Dror Helper
 
Working with c++ legacy code
Dror Helper
 
Visual Studio tricks every dot net developer should know
Dror Helper
 
Electronics 101 for software developers
Dror Helper
 
Navigating the xDD Alphabet Soup
Dror Helper
 
Who’s afraid of WinDbg
Dror Helper
 
Unit testing patterns for concurrent code
Dror Helper
 
Designing with tests
Dror Helper
 
Writing clean code in C# and .NET
Dror Helper
 
Using FakeIteasy
Dror Helper
 
Battle of The Mocking Frameworks
Dror Helper
 

Recently uploaded (20)

PDF
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 
PPTX
Presentation about Database and Database Administrator
abhishekchauhan86963
 
PPTX
Can You Build Dashboards Using Open Source Visualization Tool.pptx
Varsha Nayak
 
PPT
Why Reliable Server Maintenance Service in New York is Crucial for Your Business
Sam Vohra
 
PDF
Key Features to Look for in Arizona App Development Services
Net-Craft.com
 
PDF
Immersive experiences: what Pharo users do!
ESUG
 
PPTX
Odoo Integration Services by Candidroot Solutions
CandidRoot Solutions Private Limited
 
PPTX
slidesgo-unlocking-the-code-the-dynamic-dance-of-variables-and-constants-2024...
kr2589474
 
PDF
Summary Of Odoo 18.1 to 18.4 : The Way For Odoo 19
CandidRoot Solutions Private Limited
 
PDF
Enhancing Healthcare RPM Platforms with Contextual AI Integration
Cadabra Studio
 
PDF
vAdobe Premiere Pro 2025 (v25.2.3.004) Crack Pre-Activated Latest
imang66g
 
PPTX
ASSIGNMENT_1[1][1][1][1][1] (1) variables.pptx
kr2589474
 
PDF
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
PPT
Activate_Methodology_Summary presentatio
annapureddyn
 
PDF
Generating Union types w/ Static Analysis
K. Matthew Dupree
 
PDF
Protecting the Digital World Cyber Securit
dnthakkar16
 
PDF
An Experience-Based Look at AI Lead Generation Pricing, Features & B2B Results
Thomas albart
 
PDF
Exploring AI Agents in Process Industries
amoreira6
 
PDF
Download iTop VPN Free 6.1.0.5882 Crack Full Activated Pre Latest 2025
imang66g
 
PDF
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 
Presentation about Database and Database Administrator
abhishekchauhan86963
 
Can You Build Dashboards Using Open Source Visualization Tool.pptx
Varsha Nayak
 
Why Reliable Server Maintenance Service in New York is Crucial for Your Business
Sam Vohra
 
Key Features to Look for in Arizona App Development Services
Net-Craft.com
 
Immersive experiences: what Pharo users do!
ESUG
 
Odoo Integration Services by Candidroot Solutions
CandidRoot Solutions Private Limited
 
slidesgo-unlocking-the-code-the-dynamic-dance-of-variables-and-constants-2024...
kr2589474
 
Summary Of Odoo 18.1 to 18.4 : The Way For Odoo 19
CandidRoot Solutions Private Limited
 
Enhancing Healthcare RPM Platforms with Contextual AI Integration
Cadabra Studio
 
vAdobe Premiere Pro 2025 (v25.2.3.004) Crack Pre-Activated Latest
imang66g
 
ASSIGNMENT_1[1][1][1][1][1] (1) variables.pptx
kr2589474
 
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
Activate_Methodology_Summary presentatio
annapureddyn
 
Generating Union types w/ Static Analysis
K. Matthew Dupree
 
Protecting the Digital World Cyber Securit
dnthakkar16
 
An Experience-Based Look at AI Lead Generation Pricing, Features & B2B Results
Thomas albart
 
Exploring AI Agents in Process Industries
amoreira6
 
Download iTop VPN Free 6.1.0.5882 Crack Full Activated Pre Latest 2025
imang66g
 
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 

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

  • #4: 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.
  • #22: SHOW DEMO!
  • #35: - Two asserts – no idea what caused the failure Test is testing several things Left or right? InstanceOf MSTest vs. NUnit
  • #40: Organized Overhead
  • #41: Organized Overhead