SlideShare ist ein Scribd-Unternehmen logo
1 von 39
Downloaden Sie, um offline zu lesen
Getting	Started		
With	Testing	
Topics:
Bugs
Tests
Unit Tests
Testability
Isolation
Common Mistakes
BUGS
What	Bugs	You?	
Logical
Bugs
Wiring
Bugs
UI
Bugs
A	Bug’s	Life	
1 X
500 X
DEV PRODUCTIONQADEV TEST LAB
The cost of a bug can increase 500 times from
development to the production release.
DESIGN
0.01
X
5 X
50 X
Ineffective	Prevention	
We should code fewer bugs
We need a tool that finds all bugs
We should hire more QA people
We should have (manual) test plans
We should refactor (without tests)
There is nothing to do about it
Oops…
Effective	Prevention	
 Good Design (complexity & coupling)
 High-Level technical documentation
 Code Reviews – Fagan, Over The Shoulder, Remote
 Pair Programming
 Use logs, error logs, e-mail notification, etc.
 Write Tests (especially Unit Tests)
TESTS
Test	Types
The	Test	Pyramid	
Black Box
White Box
White Box
END TO
END
INTEGRATION
TESTS
UNIT TESTS
UNIT	TESTS
Benefits	of	writing	Unit	Tests	
1. Bugs are found (much) earlier.
2. Safer changes/refactoring (regression).
3. Up-to-date technical documentation and
examples.
4. Better low level architecture.
I	do	not	write	tests	because…	
I do not know how.
It is not my job. The QA people are paid to do that.
It is not my job. Let the customer figure what’s wrong.
I work with untestable legacy code.
I only develop UI.
It makes it difficult to refactor the code.
Requirements are not clear.
I can test everything manually.
There is no time for that.
Anatomy	of	a	Unit	Test	
Set up the needed
dependencies/para
Select a story (class
method + scenario)
Instantiate the class
Exercise/Stimulus
Run the method
Assert the expected
behavior
[TestClass]
public class CalculatorTest {
[TestMethod]
public void ShouldAddTwoPositiveIntegerNumbers() {
int addendum1 = 1;
int addendum2 = 2;
Calculator calc = new Calculator();
int sum = calc.Add(addendum1, addendum2);
Assert.AreEqual(sum, 3);
}
}
On-Field	Mission:		
Testing	The	Order	Processor	
Your Mission, should you choose to accept
it, is to unit test ValidateOrderTotal.
INPUT:
A customer id
OUTPUT:
True is the customer order for next delivery exists and the total
amount is > 0. False otherwise.
OrderProcessor processor = OrderProcessor.GetInstance();
bool isValidOrderTotal = processor
.ValidateOrderTotal("00000345-00000-000056");
Mission	Impossible?	
Mission log:
Attempt # Problem Solution
1 File Not Found Need configuration file
2 Invalid Database Set valid connection string
3 Invalid Ross Customer Id Set valid Ross Customer ID
4 Folder not found The export folder must exists and have
permissions
5 SMPT error Update SMPT configuration with valid server,
credential and set notification email
6 Order Processor Stuck Exception Delete marker file
7 Customer does not have order for next del.
date
Create order in DB for customer
8 What about the following delivery? …
… $#%k! …
… … …$#%k! $#%k!
[TestMethod]
public void CheckCustomerWithValidOrderForNextDeliveryDate() {
OrderProcessor processor = OrderProcessor.GetInstance();
bool IsValidOrderTotal = processor.ValidateOrderTotal("00000345-00000-000056");
Assert.IsTrue(IsValidOrderTotal, "...some error message...");
}
Bro!	Seriously?! 	
There should be only one reason for a unit test to fail…
Do you have the configuration file?
What is the database connection
string?
Did you set up the export folder?
Did you set up a valid SMTP server?
Did you delete the marker file?
Will the test work next week?Did you set up the Ross Customer
ID correctly?
Does the customer key exist?
Does the customer have an order
for the next delivery?
Does the customer have an order
for the next delivery?
Did you set up a customer with a
valid order total?
Did you set up a customer with an
invalid order total?
Did you set up a customer with a
valid order total?
Did you set up the maximum
waiting time?
Corpus			
Delicti		
public class OrderProcessor {
private static OrderProcessor _instance = new OrderProcessor();
private bool _isMarkerFilePresent = false;
private int _rossCustomerId = 0;
private string _exportPath = string.Empty;
private OrderProcessor() {
_exportPath = ConfigurationSettings.AppSettings["OrderExportPath"];
_isMarkerFilePresent = IOHelper.CheckMarkerFile(this._exportPath);
_rossCustomerId = Convert.ToInt32(ConfigurationSettings.AppSettings["RossCustomerID"]);
int maxSecs = Convert.ToInt32(ConfigurationSettings.AppSettings["MaxSecsToWait"]);
int secsWaited = 0;
while (_isMarkerFilePresent) {
Thread.Sleep(1000);
secsWaited += 1000;
if (secsWaited > maxSecs) {
string email = DBService.GetRossCustomerEmail(_rossCustomerId);
EmailManager.SendEmail(email, "Order Processor is stuck! Check the marker file!");
throw new Exception("Order Processor is stuck! Check the marker file!");
}
}
IOUtility.CreateMarkerFile(_exportPath, "OrderProcessor.MRK");
}
public static OrderProcessor GetInstance() { return _instance; }
public void ExportOrder(string customerId) { … }
public bool ValidateOrderTotal(string customerId) {
decimal orderTotal = 0;
Order order = DBService.GetOrder(customerId, DateTime.Now);
if (order != null) {
foreach (OrderDetail orderDetail in order.Details) {
orderTotal += orderDetail.TotalAmount;
}
}
return orderTotal>0;
}
TESTABILITY
The	Three	Factors	
Easy-to-write
meaningful
automated tests
Consistent
behavior across
multiple
deployments
Introspection
Testable	vs.	Untestable	
Dependency Injection/Transparency
Interfaces/Factories/IOC
Law Of Demeter
Seams
Single Responsibility/Layered Architecture
Composition
Simple Constructors
Idempotence
Commutativity
Implicit Dependencies
New Operator
Service Locators
Static
Mixed Concerns
Deep Inheritance
Complex Constructors
Singletons, DateTime.Now/Random
Implicit Order (hints: Init, Pre, Post, Cleanup, Load)
A	Better	Point	of	View	
Writing tests requires the code to be
testable.
Refactoring code for testability
requires time, skills and experience.
Before writing code, answer this question:
How would you like to test it?
Test	First	
Tests First = testability + small, well-isolated components
Focus on the API first and implementation later
Where did the database go?
Where is the marker file?
What happened to the configuration?
[TestMethod, TestCategory("Order Validation")]
public void OrderWithTotalAmountGreaterThanZeroShouldBeValid() {
Order order = CreateFakeOrder(totalAmount: 10.0);
IOrderValidation orderValidation = new OrderValidation(order);
bool isValidOrderTotal = orderValidation.IsValidTotal();
Assert.IsTrue(isValidOrderTotal,
"Total order amount > 0 should be valid");
}
[TestMethod, TestCategory("Order Validation")]
public void OrderWithTotalAmountZeroShouldBeInvalid() {
Order order = CreateFakeOrder(totalAmount: 0.0);
IOrderValidation orderValidation = new OrderValidation(order);
bool isValidOrderTotal = orderValidation.IsValidTotal();
Assert.IsFalse(isValidOrderTotal,
"Total order amount = 0 should be invalid");
}
[TestMethod, TestCategory("Order Validation")]
public void EmptyOrderShouldBeInvalid() {
Order order = Order.Empty;
IOrderValidation orderValidation = new OrderValidation(order);
bool isValidOrderTotal = orderValidation.IsValidTotal();
Assert.IsFalse(isValidOrderTotal,
"Empty Order should be invalid");
}
public class OrderValidation : IOrderValidation {
Order _order = Order.Empty;
public OrderValidation(Order order) {
_order = order;
}
public bool IsValidTotal() {
decimal orderTotal = 0M;
if (!_order.IsEmpty()) {
foreach (OrderDetail orderDetail in _order.Details) {
orderTotal += orderDetail.DetailAmount;
}
}
return orderTotal > 0;
}
}
ISOLATION
Controlling	the		
Test	Environment
A good unit test is like a good scientific
experiment: it isolates as many variables as
possible (these are called control variables)
and then validates or rejects a specific
hypothesis about what happens when the one variable (the
independent variable) changes.
Test Code
System Under
Test (SUT)
Dep. 1
Dep. 2
Dep. NISOLATED TEST
SEAMS
System	Under	Test	
SUT COLLABORATOR
PILOT PLANE
Test	Doubles	
Do you need a real plane?
We do not have a real plane available yet
It takes time and it is expensive to prepare a real
plane (checkup, gas, etc.)
Too dangerous, the plane may crash
If there is an issue it is hard to tell if the problem
was the pilot or the plane
Pick	your	double	
Fake Mock
Dummy Stub/Spy
Dummy
Dummy objects are passed around but never
actually used. Usually they are just used to fill
parameter lists.
public class DummyPlane implements IPlane {
public DummyPlane() {
// Real simple; nothing to initialize!
}
public int getAltitude() {
throw new RuntimeException("This should never be called!");
}
public int getSpeed() {
throw new RuntimeException("This should never be called!");
}
}
Stub/Spy
Stubs provide canned answers to calls
made during the test, usually not
responding at all to anything outside what's programmed in for
the test. Spies can record some information based on how
they were called
public class PlaneStub implements IPlane {
public PlaneStub () {
// Real simple; nothing to initialize!
}
public int getAltitude () {
log.Write(“getAltitude was called”);
return 300;
}
public int getSpeed () {
throw new RuntimeException("This should never be called!");
}
}
Fake
Fake objects actually have working
implementations, but usually take some shortcut which makes
them not suitable for production (an In Memory Database is a
good example).
public class FakePlane implements IPlane {
…
public FakePlane (FlightStatus status) {
_flightStatus = status;
}
public int getAltitude () {
return CalculateAltitude(_flightStatus);
}
public int getSpeed () {
return CalculateSpeed(_flightStatus);
}
}
Mock
Mocks are pre-programmed with expectations
which form a specification of the calls they are
expected to receive. They can throw an exception if they
receive a call they don't expect and are checked during
verification to ensure they got all the calls they were
expecting.
planeControl = MockControl.createControl(Plane.class);
planeMock = (IPlane) planeControl.getMock();
public void testPilotCheckAltitude() {
Pilot pilot = new Pilot();
planeMock.getAltitude();
planeMock.setReturnValue(300);
planeMock.replay();
pilot.Flight((IPlane) planeMock);
planeControl.verify();
}
MICROSOFT	FAKES
What	is	it?	
Microsoft Fakes is a code isolation framework that can help you isolate code for
testing by replacing other parts of the application with stubs or shims. It allows
you to test parts of your solution even if other parts of your app haven’t been
implemented or aren’t working yet.
Stubs	
[TestMethod]
public void
StubAccountOpenPostsInitialBalanceCreditTransaction()
{
// Arrange:
int callCount = 0;
StubITransactionManager stubTM = new StubITransactionManager
{
PostTransactionDecimalTransactionType = (amount, type) =>
{
if (amount == 10m && type == TransactionType.Credit)
{
callCount++;
}
}
};
Account cut = new Account(stubTM);
// Act
cut.Open(10m);
// Assert
Assert.AreEqual<int>(1, callCount);
}
Shims	(Monkey	Patching)	
Shims are a feature of Microsoft Fakes that allows creating
unit tests for code that would otherwise not be testable in
isolation. In contrast to Stubs, Shims do not require the
code to be tested be designed in a specific way.
[TestMethod]
public void DateTimeTes()
{
using (ShimsContext.Create())
{
// Arrange:
System.Fakes.ShimDateTime.NowGet = () => { return new
DateTime(2016, 2, 29); };
// Act
int result = MyCode.DoSomethingSpecialOnALeapYear();
// Assert
Assert.AreEqual(100, result);
}
}
COMMON	MISTAKES
All-In-One	
This is by far the most common mistake among beginners.
It comes in two flavors:
1. Unrelated features tested in the same test class/method
2. Single feature tested across multiple layers
Consequences: when the test fails, it is hard to point out at
what has failed
	
Long	Parking	
Tests are written correctly but they are executed rarely
and not maintained
Consequences: obsolete tests do not help preventing
bugs. They could mislead developers who read them to
try to understand the program
Where	is	the	negative?	
Other common mistake, tests are checking only what
the application should do (positive cases) and not
what it should not do (negative cases). Edge cases
and expected exception are also typically ignored by
beginners.
Consequences: poor coverage due to untested scenarios
Bad	Names	
Tests methods have names that are too
generic or meaningless. E.g. “reportTest”
or “authenticationTest”
Consequences: when the test fails, it is
not immediately obvious what has failed.
They could mislead developers who read
them to try to understand the program
Do	not	succumb	to	the	Dark	Side	
Write	Unit	Tests!	
Further Reading
Guide: Writing Testable Code
Exploring The Continuum of Test Doubles
Better Unit Testing with Microsoft Fakes
Videos
Introduction to Unit Testing in .NET
http://dotnet.dzone.com/articles/introduction-unit-testing-net
The Clean Code Talks -- Unit Testing
http://www.youtube.com/watch?v=wEhu57pih5w
GTAC 2010: Lessons Learned from Testability Failures
http://www.youtube.com/watch?v=4CFj5thxYQA

Weitere ähnliche Inhalte

Was ist angesagt?

Tutorial of web application load testing in selinium
Tutorial of web application load testing in seliniumTutorial of web application load testing in selinium
Tutorial of web application load testing in selinium
Kevalkumar Shah
 
BlackBox.pdf
BlackBox.pdfBlackBox.pdf
BlackBox.pdf
empite
 
.NET Architecture for Enterprises
.NET Architecture for Enterprises.NET Architecture for Enterprises
.NET Architecture for Enterprises
Wade Wegner
 

Was ist angesagt? (18)

Dependency Injection Pattern
Dependency Injection Pattern  Dependency Injection Pattern
Dependency Injection Pattern
 
01 introduction to entity framework
01   introduction to entity framework01   introduction to entity framework
01 introduction to entity framework
 
Refactoring legacy code driven by tests - ITA
Refactoring legacy code driven by tests -  ITARefactoring legacy code driven by tests -  ITA
Refactoring legacy code driven by tests - ITA
 
Istqb interview questions By H2KInfosys
Istqb interview questions By H2KInfosysIstqb interview questions By H2KInfosys
Istqb interview questions By H2KInfosys
 
Approaching ATDD/BDD
Approaching ATDD/BDDApproaching ATDD/BDD
Approaching ATDD/BDD
 
Manual Testing.
Manual Testing.Manual Testing.
Manual Testing.
 
Driven to Tests
Driven to TestsDriven to Tests
Driven to Tests
 
Tutorial of web application load testing in selinium
Tutorial of web application load testing in seliniumTutorial of web application load testing in selinium
Tutorial of web application load testing in selinium
 
Manual QA Testing Interview Questions From H2KInfosys
Manual QA Testing Interview Questions From H2KInfosysManual QA Testing Interview Questions From H2KInfosys
Manual QA Testing Interview Questions From H2KInfosys
 
BlackBox.pdf
BlackBox.pdfBlackBox.pdf
BlackBox.pdf
 
Black box
Black boxBlack box
Black box
 
.NET Architecture for Enterprises
.NET Architecture for Enterprises.NET Architecture for Enterprises
.NET Architecture for Enterprises
 
Manual testing interview question by INFOTECH
Manual testing interview question by INFOTECHManual testing interview question by INFOTECH
Manual testing interview question by INFOTECH
 
Learning Curve
Learning CurveLearning Curve
Learning Curve
 
Sorted
SortedSorted
Sorted
 
Refactoring for Software Design Smells
Refactoring for Software Design SmellsRefactoring for Software Design Smells
Refactoring for Software Design Smells
 
Prefer Code to Comments
Prefer Code to CommentsPrefer Code to Comments
Prefer Code to Comments
 
Inside Requirements
Inside RequirementsInside Requirements
Inside Requirements
 

Ähnlich wie Getting Started With Testing

Ähnlich wie Getting Started With Testing (20)

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
 
Unit testing - A&BP CC
Unit testing - A&BP CCUnit testing - A&BP CC
Unit testing - A&BP CC
 
Code Quality Practice and Tools
Code Quality Practice and ToolsCode Quality Practice and Tools
Code Quality Practice and Tools
 
Building unit tests correctly
Building unit tests correctlyBuilding unit tests correctly
Building unit tests correctly
 
Testes? Mas isso não aumenta o tempo de projecto? Não quero...
Testes? Mas isso não aumenta o tempo de projecto? Não quero...Testes? Mas isso não aumenta o tempo de projecto? Não quero...
Testes? Mas isso não aumenta o tempo de projecto? Não quero...
 
Stopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestStopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under Test
 
TDD Best Practices
TDD Best PracticesTDD Best Practices
TDD Best Practices
 
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
 
An introduction to unit testing
An introduction to unit testingAn introduction to unit testing
An introduction to unit testing
 
Unit tests & TDD
Unit tests & TDDUnit tests & TDD
Unit tests & TDD
 
Unit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and HowsUnit Testing - The Whys, Whens and Hows
Unit Testing - The Whys, Whens and Hows
 
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014
 
Breaking Dependencies to Allow Unit Testing
Breaking Dependencies to Allow Unit TestingBreaking Dependencies to Allow Unit Testing
Breaking Dependencies to Allow Unit Testing
 
UI Testing
UI TestingUI Testing
UI Testing
 
Pragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScriptPragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScript
 
6 Traits of a Successful Test Automation Architecture
6 Traits of a Successful Test Automation Architecture6 Traits of a Successful Test Automation Architecture
6 Traits of a Successful Test Automation Architecture
 
Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Tdd is not about testing (OOP)
Tdd is not about testing (OOP)
 
Agile mobile
Agile mobileAgile mobile
Agile mobile
 
Google test training
Google test trainingGoogle test training
Google test training
 
Unit testing with Spock Framework
Unit testing with Spock FrameworkUnit testing with Spock Framework
Unit testing with Spock Framework
 

Kürzlich hochgeladen

The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 

Kürzlich hochgeladen (20)

WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
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
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT  - Elevating Productivity in Today's Agile EnvironmentHarnessing ChatGPT  - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 

Getting Started With Testing

  • 4. A Bug’s Life 1 X 500 X DEV PRODUCTIONQADEV TEST LAB The cost of a bug can increase 500 times from development to the production release. DESIGN 0.01 X 5 X 50 X
  • 5. Ineffective Prevention We should code fewer bugs We need a tool that finds all bugs We should hire more QA people We should have (manual) test plans We should refactor (without tests) There is nothing to do about it Oops…
  • 6. Effective Prevention  Good Design (complexity & coupling)  High-Level technical documentation  Code Reviews – Fagan, Over The Shoulder, Remote  Pair Programming  Use logs, error logs, e-mail notification, etc.  Write Tests (especially Unit Tests)
  • 9. The Test Pyramid Black Box White Box White Box END TO END INTEGRATION TESTS UNIT TESTS
  • 11. Benefits of writing Unit Tests 1. Bugs are found (much) earlier. 2. Safer changes/refactoring (regression). 3. Up-to-date technical documentation and examples. 4. Better low level architecture.
  • 12. I do not write tests because… I do not know how. It is not my job. The QA people are paid to do that. It is not my job. Let the customer figure what’s wrong. I work with untestable legacy code. I only develop UI. It makes it difficult to refactor the code. Requirements are not clear. I can test everything manually. There is no time for that.
  • 13. Anatomy of a Unit Test Set up the needed dependencies/para Select a story (class method + scenario) Instantiate the class Exercise/Stimulus Run the method Assert the expected behavior [TestClass] public class CalculatorTest { [TestMethod] public void ShouldAddTwoPositiveIntegerNumbers() { int addendum1 = 1; int addendum2 = 2; Calculator calc = new Calculator(); int sum = calc.Add(addendum1, addendum2); Assert.AreEqual(sum, 3); } }
  • 14. On-Field Mission: Testing The Order Processor Your Mission, should you choose to accept it, is to unit test ValidateOrderTotal. INPUT: A customer id OUTPUT: True is the customer order for next delivery exists and the total amount is > 0. False otherwise. OrderProcessor processor = OrderProcessor.GetInstance(); bool isValidOrderTotal = processor .ValidateOrderTotal("00000345-00000-000056");
  • 15. Mission Impossible? Mission log: Attempt # Problem Solution 1 File Not Found Need configuration file 2 Invalid Database Set valid connection string 3 Invalid Ross Customer Id Set valid Ross Customer ID 4 Folder not found The export folder must exists and have permissions 5 SMPT error Update SMPT configuration with valid server, credential and set notification email 6 Order Processor Stuck Exception Delete marker file 7 Customer does not have order for next del. date Create order in DB for customer 8 What about the following delivery? … … $#%k! … … … …$#%k! $#%k! [TestMethod] public void CheckCustomerWithValidOrderForNextDeliveryDate() { OrderProcessor processor = OrderProcessor.GetInstance(); bool IsValidOrderTotal = processor.ValidateOrderTotal("00000345-00000-000056"); Assert.IsTrue(IsValidOrderTotal, "...some error message..."); }
  • 16. Bro! Seriously?! There should be only one reason for a unit test to fail… Do you have the configuration file? What is the database connection string? Did you set up the export folder? Did you set up a valid SMTP server? Did you delete the marker file? Will the test work next week?Did you set up the Ross Customer ID correctly? Does the customer key exist? Does the customer have an order for the next delivery? Does the customer have an order for the next delivery? Did you set up a customer with a valid order total? Did you set up a customer with an invalid order total? Did you set up a customer with a valid order total? Did you set up the maximum waiting time?
  • 17. Corpus Delicti public class OrderProcessor { private static OrderProcessor _instance = new OrderProcessor(); private bool _isMarkerFilePresent = false; private int _rossCustomerId = 0; private string _exportPath = string.Empty; private OrderProcessor() { _exportPath = ConfigurationSettings.AppSettings["OrderExportPath"]; _isMarkerFilePresent = IOHelper.CheckMarkerFile(this._exportPath); _rossCustomerId = Convert.ToInt32(ConfigurationSettings.AppSettings["RossCustomerID"]); int maxSecs = Convert.ToInt32(ConfigurationSettings.AppSettings["MaxSecsToWait"]); int secsWaited = 0; while (_isMarkerFilePresent) { Thread.Sleep(1000); secsWaited += 1000; if (secsWaited > maxSecs) { string email = DBService.GetRossCustomerEmail(_rossCustomerId); EmailManager.SendEmail(email, "Order Processor is stuck! Check the marker file!"); throw new Exception("Order Processor is stuck! Check the marker file!"); } } IOUtility.CreateMarkerFile(_exportPath, "OrderProcessor.MRK"); } public static OrderProcessor GetInstance() { return _instance; } public void ExportOrder(string customerId) { … } public bool ValidateOrderTotal(string customerId) { decimal orderTotal = 0; Order order = DBService.GetOrder(customerId, DateTime.Now); if (order != null) { foreach (OrderDetail orderDetail in order.Details) { orderTotal += orderDetail.TotalAmount; } } return orderTotal>0; }
  • 20. Testable vs. Untestable Dependency Injection/Transparency Interfaces/Factories/IOC Law Of Demeter Seams Single Responsibility/Layered Architecture Composition Simple Constructors Idempotence Commutativity Implicit Dependencies New Operator Service Locators Static Mixed Concerns Deep Inheritance Complex Constructors Singletons, DateTime.Now/Random Implicit Order (hints: Init, Pre, Post, Cleanup, Load)
  • 21. A Better Point of View Writing tests requires the code to be testable. Refactoring code for testability requires time, skills and experience. Before writing code, answer this question: How would you like to test it?
  • 22. Test First Tests First = testability + small, well-isolated components Focus on the API first and implementation later Where did the database go? Where is the marker file? What happened to the configuration? [TestMethod, TestCategory("Order Validation")] public void OrderWithTotalAmountGreaterThanZeroShouldBeValid() { Order order = CreateFakeOrder(totalAmount: 10.0); IOrderValidation orderValidation = new OrderValidation(order); bool isValidOrderTotal = orderValidation.IsValidTotal(); Assert.IsTrue(isValidOrderTotal, "Total order amount > 0 should be valid"); } [TestMethod, TestCategory("Order Validation")] public void OrderWithTotalAmountZeroShouldBeInvalid() { Order order = CreateFakeOrder(totalAmount: 0.0); IOrderValidation orderValidation = new OrderValidation(order); bool isValidOrderTotal = orderValidation.IsValidTotal(); Assert.IsFalse(isValidOrderTotal, "Total order amount = 0 should be invalid"); } [TestMethod, TestCategory("Order Validation")] public void EmptyOrderShouldBeInvalid() { Order order = Order.Empty; IOrderValidation orderValidation = new OrderValidation(order); bool isValidOrderTotal = orderValidation.IsValidTotal(); Assert.IsFalse(isValidOrderTotal, "Empty Order should be invalid"); } public class OrderValidation : IOrderValidation { Order _order = Order.Empty; public OrderValidation(Order order) { _order = order; } public bool IsValidTotal() { decimal orderTotal = 0M; if (!_order.IsEmpty()) { foreach (OrderDetail orderDetail in _order.Details) { orderTotal += orderDetail.DetailAmount; } } return orderTotal > 0; } }
  • 24. Controlling the Test Environment A good unit test is like a good scientific experiment: it isolates as many variables as possible (these are called control variables) and then validates or rejects a specific hypothesis about what happens when the one variable (the independent variable) changes. Test Code System Under Test (SUT) Dep. 1 Dep. 2 Dep. NISOLATED TEST SEAMS
  • 26. Test Doubles Do you need a real plane? We do not have a real plane available yet It takes time and it is expensive to prepare a real plane (checkup, gas, etc.) Too dangerous, the plane may crash If there is an issue it is hard to tell if the problem was the pilot or the plane
  • 28. Dummy Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists. public class DummyPlane implements IPlane { public DummyPlane() { // Real simple; nothing to initialize! } public int getAltitude() { throw new RuntimeException("This should never be called!"); } public int getSpeed() { throw new RuntimeException("This should never be called!"); } }
  • 29. Stub/Spy Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Spies can record some information based on how they were called public class PlaneStub implements IPlane { public PlaneStub () { // Real simple; nothing to initialize! } public int getAltitude () { log.Write(“getAltitude was called”); return 300; } public int getSpeed () { throw new RuntimeException("This should never be called!"); }
  • 30. } Fake Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an In Memory Database is a good example). public class FakePlane implements IPlane { … public FakePlane (FlightStatus status) { _flightStatus = status; } public int getAltitude () { return CalculateAltitude(_flightStatus); } public int getSpeed () { return CalculateSpeed(_flightStatus); } }
  • 31. Mock Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting. planeControl = MockControl.createControl(Plane.class); planeMock = (IPlane) planeControl.getMock(); public void testPilotCheckAltitude() { Pilot pilot = new Pilot(); planeMock.getAltitude(); planeMock.setReturnValue(300); planeMock.replay(); pilot.Flight((IPlane) planeMock); planeControl.verify(); }
  • 33. What is it? Microsoft Fakes is a code isolation framework that can help you isolate code for testing by replacing other parts of the application with stubs or shims. It allows you to test parts of your solution even if other parts of your app haven’t been implemented or aren’t working yet.
  • 34. Stubs [TestMethod] public void StubAccountOpenPostsInitialBalanceCreditTransaction() { // Arrange: int callCount = 0; StubITransactionManager stubTM = new StubITransactionManager { PostTransactionDecimalTransactionType = (amount, type) => { if (amount == 10m && type == TransactionType.Credit) { callCount++; } } }; Account cut = new Account(stubTM); // Act cut.Open(10m); // Assert Assert.AreEqual<int>(1, callCount); }
  • 35. Shims (Monkey Patching) Shims are a feature of Microsoft Fakes that allows creating unit tests for code that would otherwise not be testable in isolation. In contrast to Stubs, Shims do not require the code to be tested be designed in a specific way. [TestMethod] public void DateTimeTes() { using (ShimsContext.Create()) { // Arrange: System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(2016, 2, 29); }; // Act int result = MyCode.DoSomethingSpecialOnALeapYear(); // Assert Assert.AreEqual(100, result); } }
  • 37. All-In-One This is by far the most common mistake among beginners. It comes in two flavors: 1. Unrelated features tested in the same test class/method 2. Single feature tested across multiple layers Consequences: when the test fails, it is hard to point out at what has failed Long Parking Tests are written correctly but they are executed rarely and not maintained Consequences: obsolete tests do not help preventing bugs. They could mislead developers who read them to try to understand the program
  • 38. Where is the negative? Other common mistake, tests are checking only what the application should do (positive cases) and not what it should not do (negative cases). Edge cases and expected exception are also typically ignored by beginners. Consequences: poor coverage due to untested scenarios Bad Names Tests methods have names that are too generic or meaningless. E.g. “reportTest” or “authenticationTest” Consequences: when the test fails, it is not immediately obvious what has failed. They could mislead developers who read them to try to understand the program
  • 39. Do not succumb to the Dark Side Write Unit Tests! Further Reading Guide: Writing Testable Code Exploring The Continuum of Test Doubles Better Unit Testing with Microsoft Fakes Videos Introduction to Unit Testing in .NET http://dotnet.dzone.com/articles/introduction-unit-testing-net The Clean Code Talks -- Unit Testing http://www.youtube.com/watch?v=wEhu57pih5w GTAC 2010: Lessons Learned from Testability Failures http://www.youtube.com/watch?v=4CFj5thxYQA