IUST Advanced software engineering course by Dr. Saeed Parsa. Credits of slides belong to Dr. Saeed Parsa and IUST reverse engineering research laboratory. All slides are available publicly due to COVID 19 Pandemic.
4. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 4
• Test driven development (TDD) is a software development approach.
• In TDD a test is written before writing the code.
• Once the new code passes the test, it is refactored to an acceptable
standard.
TDD ensures that the source code is thoroughly unit tested and leads
to modularized, flexible and extensible code.
TDD focuses on writing only the code necessary to pass tests, making
the design simple and clear.
5. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 5
• The test is written before testing the
functionality
• Ensures that the application is suitable for
testability.
• The functionality is implemented.
• This is referred to as "red green refactor.
• Red means fail and green shows a pass.
• These steps are repeated.
o The first goal of a programmer is to focus
on the task at hand and to pass it.
7. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 7
TDD can lead to more modularized, flexible, and extensible code
Clean code
Leads to better design
Better code documentation
More productive
Good design
8. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 8
My goal is for you to see the rhythm of test-driven development:
1. Quickly add a test
2. Run all tests and see the new one fail
3. Make a little change
4. Run all tests and see them all succeed
5. Refactor to remove duplication
The surprises are likely to be:
How each test can cover a small increment of functionality
How small and ugly the changes can be to make the new tests run
How often the tests are run
How many teensy tiny steps make up the refactorings
9. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 9
1. Create class-diagram/Components-model using a class designer
2. Generate code from the diagram
3. Select a method to test
4. Generate test using Nunit, Junit, …
5. Run the test
6. The test fails
7. Complete the selected method
8. The test passes
9. Clean the code
10. Refactor the code
11. repeat
Unit testing requires that the source code is composed in
such a way that dependencies between modules can be
easily neutralized with mocks. In addition, unit testing
requires that functions are well isolated from each other
10. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 10
Consider the class diagram, shown in the next slide.
The diagram is depicted in the Enterprise Architect environment.
Generate C# code from the class diagram.
Make a C# console application(.sln file).
Add the generated classes to the console application.
Use Nunit to generate test classes and unit test.
14. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 14
///////////////////////////////////////////////////////////
// point.cs
// Implementation of the Class point
// Generated by Enterprise Architect
// Created on: 09-Apr-2020 5:44:14 PM
// Original author: Asus
///////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Geometry;
namespace Geometry {
public class point : GraphicalObject {
15. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 15
public double x;
public double y;
public point(){
}
~point(){
}
///
/// <param name="xCoord"></param>
/// <param name="yCoord"></param>
public point(double xCoord, double yCoord){
}
16. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 16
/// <param name="p"></param>
/// <param name="q"></param>
public static double dist(point p, point q){
return 0;
}
///
/// <param name="p"></param>
/// <param name="q"></param>
public static double distPower2(point p, point q){
return 0;
}
public void draw(){
}
17. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 17
public void dump(){
}
///
/// <param name="p"></param>
/// <param name="q"></param>
/// <param name="r"></param>
public static bool isCoLinear(point p, point q, point r){
return false;
}
///
/// <param name="aPoint"></param>
public Boolean isEqual(point aPoint){
return null;
}
18. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 18
///
/// <param name="xc"></param>
/// <param name="yc"></param>
/// <param name="angel"></param>
public void rotate(int xc, int yc, double angel){
}
///
/// <param name="x_val"></param>
/// <param name="y_val"></param>
public void Set(double x_val, double y_val){
}
}//end point
}//end namespace Geometry
23. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 23
Use NUnit3 in visual studio environment to create test classes.
If Nunit is not installed you will have to install it.
Right click on the name of the method to be tested.
Select “Create unit test option”
A unit is the smallest possible part of a program that can be logically isolated
and tested.
A method, function, procedure, or subroutine is an instance of a unit. Unit
testing is the first phase of testing.
As an example, consider the class point, in C#, listed below:
24. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 24
public class point : GraphicalObject
{
private double x, y;
public point(double xCoord, double yCoord){}
public void Set(double x_val, double y_val) {}
// Computes the distance between the points P and q.
public static double dist(point p, point q) {}
public static double distPower2(point p, point q){}
// Determines whether
public static bool isCoLinear(point p, point q, point r){}
public void dump(){}
public Boolean isEqual(point aPoint){}
// Rotates the point object around the point (xc, yc) for angle.
public void rotate(int xc, int yc, double angel){}
public void draw(){}
}
25. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 25
A unit is the smallest possible part of a program that can be logically isolated
and tested.
A method, function, procedure, or subroutine is an instance of a unit. Unit
testing is the first phase of testing.
As an example, right click on the name of the method “dist” in the class
“point”,
public static double dist(point p, point q) { … }
Select the “create test” option as shown in the bext slide.
If “Nunit” is not installed click on the “Get additional extensions”.
29. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 29
1. Test Cases are copied
into x1, y1, x2 and y2,
respectively.
2. Result is compared
with the retuen value.
30. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 30
The test cases show two points
and their expected distances.
Eg.
[TestCase(0,0, 1,0, Result = 1)]
P1 = (0,0) , P2 = (1,0)
dist(P1, P2) = 1
To run tests select:
Test->Run All Tests
To view test results:
Test->Test Explorer
31. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 31
The previous test fails.
Complete the body of the “dist” method as follows:
// Computes the distance between the points p and q
public static double dist(point p, point q)
{
double res = 0;
if (p.x == q.x) { res = Math.Abs(p.y - q.y); return res; }
if (p.y == q.y) { res = Math.Abs(p.x - q.x); return res; }
double dx = p.x - q.x; double dy = p.y - q.y;
res = Math.Sqrt(dx * dx + dy * dy);
return res;
}
32. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 32
Run the tests again:
Test->Run All Tests
To view test results:
Test->Test Explorer
33. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 33
Complete the test method.
The test fails:
[Test()]
[TestCase(0, 0, 90, 2, 0, Result = new double[2] { 0, 2 })]
[TestCase(0, 0, 90, 1, 1, Result = new double[2] { 0, 1 })]
[TestCase(0, 0, 90, 1, 0, Result = new double[2] { 0, 1 })]
public double[] rotateTest(int xc, int yc, double angel, double x, double y)
{
point p = new point(x, y);
p.rotate(xc, yc, angel);
var result = new double[2];
result[0] = p.x;
result[1] = p.y;
Console.Write(" (x = {0}), y={1}", p.x, p.y);
return result;
}
34. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 34
The previous test fails.
Complete the body of the “rotate” method as follows:
// Rotates “this” object around point (xc, yc) for angle anel1 degree
public void rotate(int xc, int yc, double angel)
{
//point ComparedWith = new point(xc, yc);
angel = angel*3.141592/180;
if (xc == x && yc == y) return;
else
{
double cosa = Math.Cos(angel); double sina = Math.Sin(angel);
double dx = x - xc; double dy = y - yc;
x = (int)Math.Round(cosa * dx - sina * dy + xc);
y = (int)Math.Round(sina * dx + cosa * dy + yc);
}
}
36. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 36
Write all the test cases for testing the “dist” method in a text file, testCases.txt.
0,0,0,1,1
0,0,2,0,2
0,0,3,4,5
0,0,0,0,0
37. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 37
namespace Geometry.Tests
{
[TestFixture()]
public class pointTests
{[Test, TestCaseSource(typeof(MyTestCases), "TestCasesFromFile")]
//[Test, TestCaseSource(typeof(MyTestCases), "TestCases")]
public double distTest(point p, point q)
{
var result = point.dist(p, q);
p.dump(); q.dump(); Console.WriteLine(" distance = {0}", result);
return result;
}
}
38. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 38
public class MyTestCases
{public static IEnumerable TestCasesFromFile
{ get
{ using (StreamReader file = new StreamReader(@"D:TestCases.txt"))
{ string ln;
while ((ln = file.ReadLine()) != null)
{ string[] values = ln.Split(',');
point p = new point(Convert.ToDouble(values[0]),
Convert.ToDouble(values[1]));
point q = new point(Convert.ToDouble(values[2]),
Convert.ToDouble(values[3]));
yield return new TestCaseData(p,
q).Returns(Convert.ToDouble(values[4]));
}
}
}
} } }
40. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 40
Requirements:
toRoman:
should return the Roman numeral representation for all integers 1 to 3999.
should always return a Roman numeral using uppercase letters.
fromRoman:
should take a valid Roman numeral and return the number that it represents.
should only accept uppercase Roman numerals (i.e. it should fail when
given lowercase input).
41. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 41
#roman.py
"""Convert to and from Roman numerals"""
#Define exceptions
class RomanError(Exception): pass
class OutOfRangeError(RomanError): pass
class NotIntegerError(RomanError): pass
class InvalidRomanNumeralError(RomanError): pass
def toRoman(n):
"""convert integer to Roman numeral"""
pass
def fromRoman(s):
"""convert Roman numeral to integer"""
pass
42. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 42
Unittest: testRoman.py
"""Unit test for roman.py"""
import roman
import unittes
knownValues = ( (1, 'I'),.,.,.,..,(3999, 'MMMCMXCIX'))
class TestToRoman(unittest.TestCase):
def testToRomanGood(self):
"""toRoman should give known result with known input"""
for integer, numeral in knownValues:
result = roman.toRoman(integer)
self.assertEqual(numeral, result)
def testNonInteger(self):
"""toRoman should fail with non-integer input"""
self.assertRaises(roman.NotIntegerError, roman.toRoman, 0.5)
43. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 43
class TestFromRoman(unittest.TestCase):
def setup(self):
pass
def tesrdown(self):
pass
def test_knownValues(self):
"""fromRoman should give known result with known input"""
for integer, numeralin knownValues:
result = roman.fromRoman(numeral)
self.assertEqual(integer, result)
def testTooManyRepeatedNumerals(self):
"""fromRoman should fail with too many repeated numerals"""
for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)
44. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 44
"""Convert to and from Roman numerals"""
#Define exceptions
class RomanError(Exception): pass
class OutOfRangeError(RomanError): pass
class NotIntegerError(RomanError): pass
class InvalidRomanNumeralError(RomanError): pass
#Define digit mapping
romanNumeralMap = (('M', 1000), ('CM', 900), ('D', 500),('CD',
400), ('C', 100), ('XC', 90), ('L', 50),('XL', 40), ('X', 10), ('IX', 9), ('V',
5), ('IV', 4), ('I', 1))
45. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 45
def toRoman(n):
"""convert integer to Roman numeral"""
if not (0 < n < 4000):
raise OutOfRangeError, "number out of range (must be 1..3999)"
if int(n) <> n:
raise NotIntegerError, "non-integers can not be converted"
result = ""
for numeral, integer in romanNumeralMap:
while n >= integer:
result += numeral
n -= integer
return result
def fromRoman(s):
"""convert Roman numeral to integer"""
pass
46. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 46
def fromRoman(s):
"""convert Roman numeral to integer"""
result = 0
index = 0
for numeral, integer in romanNumeralMap:
while s[index:index+len(numeral)] == numeral:
result += integer
index += len(numeral)
return result
47. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 47
The nose.tools module provides a number of testing aids:
Decorators: for restricting test execution time and testing for exceptions,
Assert: methods found in unittest.TestCase (only spelled in pep08 fashion, so
assert_equal rather than assertEqual).
nose.tools.raises(*exceptions)
Test must raise one of expected exceptions to pass.
Example use:
@raises(TypeError, ValueError)
def test_raises_type_error():
raise TypeError("This test passes")
nose.tools.assert_equal
-- Fail if the two objects are unequal
-- as determined by the ‘==’ operator.
nose.tools.assert_false
-- Fail the test if the expression is true.
48. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 48
The overall architecture of the payroll application software consists of three packages.
49. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 49
The “Guard interface” and “Time card reader” are two parallel tasks.
50. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 50
There is a time card reader in
the payroll department, as
well.
51. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 51
To assign a class to a component (In Rational-Rose environment) by:
1. Click on the component.
2. A list of all the classes will pop up.
3. Click on the name of a class,
4. Assign the class to the component.
54. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 54
• [1] Erdogmus, Hakan; Morisio, Torchiano. On the Effectiveness of Test-first Approach to
Programming. Proceedings of the IEEE Transactions on Software Engineering, 31(1). January 2005.
(NRC 47445). Retrieved on 2008-01-14.
• [2] George, Boby; Williams, Laurie. A Structured experiment of test-driven development. 2003.
• [3] E.M. Maximilien, L. Williams; Assessing test-development at IBM, presented at International
Conference of Software Engineering, Portland, OR, 2003.
• [4] Beck, K. Test-Driven Development by Example, Addison Wesley, 2003
http://en.wikipedia.org/wiki/Test_driven_development#Test-Driven_Development_Cycle
• [5] JMock.org, www.jmock.org, Year ?
55. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 55
• What?
• Software testing is the art of measuring and maintaining software quality.
• Why?
• To ensure that user expectations and requirements, business value, non-
functional requirements, such as security, reliability and recoverability,
and operational policies are all met.
• How?
• Testing strategies: Black, white, and gray box testing.*
56. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 56
• How?
• Testing strategies are traditionally divided into black, white, and gray box
testing.
- Black: The inside of the box (“solution implementation”) is dark. Testers focus only on
input and output, typically when performing system and user acceptance testing.
- White: The inside of the box is visible and analyzed as part of the testing.
- Gray: A combination of black and white box testing typically used to test edge cases,
which require an understanding of the internals and expected behavior.
60. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 60
• Microsoft Fakes is a new 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.
• Microsoft Fakes come in two flavors:
Stubs … replace a class with a small substitute (“stub”) that implements the
same interface.
Shims … modify the compiled code at run time, to inject and run a substitute
(“shim”).
• Stubs are typically used for calls within your solution that you can decouple using
interfaces; shims are used for calls to referenced assemblies for which the code is
not under your control.
61. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 61
• Fakes come in two flavours:
• A shim modifies the compiled code of your application at run time so that
instead of making a specified method call, it runs the shim code that your test
provides. Shims can be used to replace calls to assemblies that you cannot
modify, such .NET assemblies.
• A stub replaces a class with a small substitute that implements the same
interface. To use stubs, you have to design your application so that each
component depends only on interfaces, and not on other components.
62. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 62
We have a class that implements something depends on System library.
using System;
namespace DemoClassLibrary
{
public class Foo
{
public long UtcNowTick()
{
return DateTime.UtcNow.Ticks;
}
}
}
So this UtcNowTick is depends on the
DateTime, and right now we want to test this
function
This is a typical scenario for us to use shim to
test because we cannot control the behaviour
of the system library.
63. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 63
• Add the fake to the desired library
As a result a fake assembly will be created:
after-add-fake.jpg
64. 4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir) 64
So right now, we have the fake assembly for system now, and we can
control the behaviour of system namespace api as below:
65. Resources – TDD & refactoring
test-driven development:
A Practical Guide
Dave Astels
Prentice-Hall/Pearson Education, 2003
ISBN 0-13-101649-0
___________________________
Test-Driven Development:
By Example
Kent Beck
Addison-Wesley, 2003
ISBN 0-321-14653-0
654/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir)
66. Resources – TDD & refactoring
Agile Java - Crafting Code
with Test-Driven
Development
Jeff Langr
Prentice Hall 2005
ISBN 0-13-148239-4
66
4/20/2020 S. Parsa, Associate Professor (www.parsa.iust.ac.ir)