(Updated) Week 06 - Lecture 2021

You might also like

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 57

KF7010

Well Behaved Objects


Lauren Scott
(closely based on the work of
Dr Mark C. Sinclair)

Semester 1, 2022-23
Errors, Black-box &
White-box Testing
We have to deal with
errors
• Early errors are usually syntax errors
– The compiler will spot these
– These are errors with the Java code that the compiler
can’t process
• Later errors are usually logic errors
– The compiler cannot help with these
– These are errors we as programmers make that cause
unexpected outputs.
– Also known as bugs
• Some logical errors have no immediately obvious
manifestation
– Commercial software is rarely error free
Prevention vs Detection
(Developer vs Maintainer)
• We can lessen the likelihood of errors
– Use software engineering techniques, like
encapsulation
• We can improve the chances of
detection
– Use software engineering practices, like
modularisation and documentation
• We can develop detection skills
Testing and debugging
• These are crucial skills
• Testing searches for the presence of
errors
• Debugging searches for the source of
errors
– The manifestation of an error may well
occur some ‘distance’ from its source
Approaches to Test
Case Generation
Black Box Testing
inputs outputs

No knowledge of code

• Test designer ignores internal structure


of implementation
• Test driven by expected external behavior of
the system
• System is treated as a “black box”:
• behavior can be observed
• but internal structure is unknown
Test design, test cases
and test plan
• Test design generally begins with an
analysis of
– Functional specifications of system
– Use cases: ways in which the system will be used
• A test case is defined by
– Statement of case objectives
– Data set for the case
– Expected results
• A test plan is a set of test cases
Par tition the input
space
• Input space is very large, but
program is small
– so behavior must be the “same” for whole
sets of inputs
• Ideal test suite
– identify sets of inputs with the same
behavior
– try one input from each set
Boundar y testing
• Include cases at boundaries of the
input space
– zero, min/max values, empty set, empty
string, null
• why?
– because bugs often occur at boundaries
• off-by-one errors
• forget to handle empty container
• overflow errors in arithmetic
White box testing
inputs outputs

Use code to help design


test cases

• Tests for a module are developed based upon


its implementation
• Knowledge of implementation is used to select
test cases
– Code contains an if-else statement:
• Write tests for both branches of if-else
White box testing
• Need a guiding criteria to help select
test cases
– Statement coverage
• All statements in unit exercised
– Branch coverage
• All true/false outcomes exercised at least
once
– Multiple condition coverage
• See next slide
Multiple Condition
Coverage (MCC)
Multiple condition
coverage

• All possible combinations of


condition outcomes in each decision
must be invoked at least once under
some test
Example
if ( (a > 1) && ( b == 0) )
x = x / a; We have three
if ( (a == 2) && ( x > 1) ) variables.
int a, b
x++; float
x
Want test data which
satisfies MCC
Step 1 : Produce truth
tables
a>1 b==0 (a>1) && (b==0)
1 T T T
Number each entry 2 T F F
3 F T F
4 F F F

a==2 x>1 (a==2) && (x>1)


5 T T T
6 T F F
7 F T F
8 F F F
Step 2 : Find values for a,
b, x
Select entry in first table. Select possible entry in second
table See if we can find values

Select entries 1 and 5


This means we want values for a, b and x so that
(a > 1) (b == 0 ) (a == 2) ( x > 1)
Gives a = 2, b = 0. What about x?
We want input value for x. By the time we reach condition
this value modified as: x = x / = x / 2 > 1 so x >2
a Say x = 3
Test data { a = 2, b = 0, x = 3}
Description of Method
1. Produce truth tables for all decision
expressions in the program,
numbering each entry
2. Check the truth table to remove any
impossible entries
3. Produce a minimal number of test
cases such that each entry in
the tables has been invoked at
least once (some may be used
several times)
Learn by example

public class Counter {


// count should only take positive values. 0 is positive
private int count;
public Counter() { count = 0; } public
Counter(int i) { count = i; }
public void setCounter(int i) {
count = i; }
public int getCounter() { return count; }
public void incCounter() { count++; }
private boolean okCounter() { return count > 0; } public
void decCounter() { if ( okCounter() ) count--; }
}
Categories of methods
Constructors Counter() public

Counter( int i) public

Queries getCounter() public

okCounter() private

Commands setCounter(int i) public

incCounter() public

decCounter() public
Observation
s
• First thing we must do is test a
constructor
– How do we observe the results?
– Test getCounter() at same time?
• with one attribute okay, but may not always be
so
– The more methods tested at one go the
more difficult it is to track down any bugs
Java solution
toString
toString
• Every class is a subclass of Object
• Object has a method
String toString()
• For each of our classes, we should
create a toString() method. (Overiding
the objects default toString)
• E.g. for Counter we use
public String toString()
{ return "" +
counter; }
toString
• We have used these methods before, when using
variables from of different data types. Such as
when we converted our students’ IDs from integer
to string:
Integer.toString(ID)

• But, when we would want to print the ID all we


would need to type is:
System.out.println(ID);

It prints the String value of the ID. Our toString
methods will work the same way, printing the
current state of objects.
• Recommend always have a toString()
Test Driver Where is the
toString()?
public class DriverForCounter {
public static void main(String[] args)
{
System.out.println ("Test of Default
Constructor");
// test the default constructor
Counter c = new Counter();
// test the method toString
System.out.println(c);
}
}
Hidden in println(c). You do not need to write
c.toString(). Java will invoke
automatically
Test Drivers
• Supplies test data
• Catches the results
• Start with one driver per method
• Subsequently, multiple test methods
can be called from a single main

Remember the place a fault appears may


not be the source of the error!
Summary
of
• Ideally all classes should have a
Approach
toString() method

De stab
• Test the constructors first

Te
sig ili
n
• Test public query methods

fo
r
ty
next
• Test public commands next
• Initially write drivers to test one and
only one method at a time
• When the initial testing is complete
drivers may be merged as appropriate
Worked Example: Using MCC
Counter() No values
Counter(int i) A positive integer
getCounter() No input
toString() No input
okCounter() count +ve count 0
setCounter(int i) A positive integer
incCounter() No input
decCounter() count +ve; count 0
JUnit
Unit testing
• Each unit of an application may be tested
– Method, class, package, module (in Java)
• Should be done during development
– Finding and fixing early lowers development costs
(e.g. programmer time)
– A test suite is built up
Unit testing within BlueJ
• In BlueJ, objects of individual classes
can be created
• Individual methods can be invoked
• Inspectors provide an up-to-date view
of an object’s state
• But more it supports JUnit
4.11
JUnit
• JUnit is a framework for writing tests
– JUnit uses Java’s reflection capabilities
(Java programs can examine their own code)
– JUnit helps the programmer:
• define and execute tests and test suites
• formalise requirements and clarify architecture
• write and debug code
• integrate code and always be ready to release a
working version
– JUnit API (not part of Java API):
https://junit.org/junit4/javadoc/latest/
Terminology
• A test fixture sets up the data that
are needed to run tests
– Example: If you are testing code that updates an
employee record, you need an employee record to
test it on
• A unit test is a test of a single class
• A test case tests the response of a
single method to a particular set of
inputs
• A test suite is a collection of test cases
JUnit operation
• Within a test:
– Call the method being tested and get the actual
result
– Assert what the correct result should be using one
of the provided assert methods
– These steps can be repeated as many times as
necessary
• An assert method is a JUnit method that
performs a simple test, and throws an
AssertionFailedError if the test fails
• JUnit catches these Errors and shows
you the result
Assert methods
• I
static void assertTrue(boolean condition)
static void assertTrue(boolean
Condition, String message, )

• static void assertFalse(boolean condition)


static void assertFalse(boolean
condition String message, )
Assert methods

II
assertEquals(expected, actual)
assertEquals(String message, expected, actual)

• assertSame(Object expected, Object actual)


assertSame(String message, Object expected,
Object actual)

• assertNotSame(Object expected, Object actual)


assertNotSame(String message, Object expected,
Object actual)
Assert methods

III
assertNull(Object object)
assertNull(String message, Object object)

• assertNotNull(Object object)
assertNotNull(String message, Object object)

• fail()
fail(String message)
What JUnit does
• JUnit runs a suite of tests and reports
results
• For each test in the test suite:
– JUnit calls setUp()
• This method should create any objects you may
need for testing
• Indicated by @Before annotation
What JUnit does


– JUnit calls one test method
The test method may comprise multiple test
cases; that is, it may make multiple calls to the
method you are testing
• Marked with @Test annotation
• In fact, since it’s your code, the test method
can do anything you want
• The setUp() method ensures you entered the
test method with a virgin set of objects; what
you do with them is up to you
– JUnit calls tearDown()
• This method should remove any objects you
created
• Marked with @After annotation
Test classes in BlueJ
The class The menu you
The class to to test it get when you
be tested right-click
the test class

Use these
to run tests

Use
these to
create
tests
Creating a test class in
BlueJ
• If you have an existing class, right-click
on it and choose Create Test Class
– If your class is named MyClass, the new test
class will be named MyClassTest
Creating the setUp()
method
• BlueJ has an Object Bench
– You can create objects on the Object Bench by
right-clicking on a class and choosing one of its
new constructors
• You can right-click on a test class and
choose:
– Object Bench To Test Fixture or
– Test Fixture To Object Bench
• Since setUp() is your code, you can modify it
any way you like (such as creating new objects
in it)
Implementing the tearDown()
method
• In most cases, the tearDown() method
doesn’t need to do anything
– The next time you run setUp(), your
objects will be replaced, and the old
objects will be available for
garbage collection
– It doesn’t hurt to set to null the objects
you created in setUp()
Recording test cases
• An easy way to create a test method is to
right-click a compiled test class and choose
Create Test Method...
– Enter the name of the method you want to test
– It is usually a good idea to give them a name
with 'test' at the beginning
– If you wish, you can copy Test Fixture To Object
Bench
Recording test cases…
– Use BlueJ to make calls to the method
• After each call, BlueJ will tell you its result, and ask you
to type in the result you expected
– The result can be equal to, the same as, not the same as,
null, not null, or equal to (double or float)
• You can even create a new object to use as a result
– When you are done click the End button (under
Recording)
The structure of a test
method
• A test method doesn’t return a result
• If the tests runs correctly, a test
method does nothing
• If a test fails, it throws an
AssertionFailedError
– Hence, a test method just calls one or more
assertion methods, any of which may throw an
AssertionFailedError
• The JUnit framework catches the error and
deals with it; you don’t have to do
anything
Testing Example –
Counter test
public class Counter {
// count should only take positive values.
// 0 is positive
private int count;

public Counter() { count = 0; }


public Counter( int i) { count =
i; }
public void setCounter( int i) { count =
i; } public int getCounter() { return
count; } public void incCounter() { count+
+; }
private boolean okCounter() { return count > 0; }
public void decCounter() { if ( okCounter() )
count--;}
public String toString() { return ""+count; }
Tests for the default
constructor
public Counter() { count = 0; }

• want to know if it is created


– object not null
• want to know the value of count
– need to use toString()
• assume it works
• so ..
•right click on Counter
•select Create Test Class
•right-click on CounterTest
•select Create Test Method
•enter a name for the test in the dialogue box

•hit OK
•the recording light comes on
•create a new Counter object using the default
constructor
• hit the End button
•look at code in CounterTest
public void testDefaultConstructorT1()
{
Counter counter1 = new Counter();
}
• Need to add an assert manually

public void testDefaultConstructorT1()


{
Counter counter1 = new Counter();
assertNotNull(counter1);
}
• repeat the
steps to create
a second test
for the default
constructor but
this time call
toString() after
creating the
object

enter a value
• end recording
public void testDefaultConstructorT1()
{
Counter counter1 = new Counter();
assertNotNull(counter1);
}
public void testDefaultConstructorT2()
{
Counter counter1 = new Counter();
assertEquals("0", counter1.toString());
}
Run tests
Change code in the default constructor, say count = 1;
Fixtures
• Test methods often require you to set up the
same sets of objects for each test
• A group of such objects is know as a fixture
• We can use Object Bench to Fixture to have
these placed in the method setUp() which
is called before every test
protected void setUp()
{
counter1 = new Counter();
}
//tearDown() goes here but does nothing

public void
testDefaultConstructorT1()
{
assertNotNull(counter1);
}

public void
testDefaultConstructorT2()
{
assertEquals("0",
counter1.toString());

You might also like