APP Lab. 7 Lecture 20.01.2024
APP Lab. 7 Lecture 20.01.2024
APP Lab. 7 Lecture 20.01.2024
understandable
easy to maintain
repeatable
granular
fast
Unit testing principles
● The goal is to verify the actual behavior of a single instance
(object) of a given class with the expected behavior
● The effect of the method called for the tested object is checked for
various arguments (parameters), the returned values are
examined
● There is at least one test case for each method - there should be
one test case for each type of initial condition and arguments
● Test cases related to one test object are gathered inside one test
class
Testing with … main() { …} ?
public class ArithmeticService {
Hamcrest
Unit testing on the example of JUnit
● JUnit it is a tool - programming platform - a framework within Java
technology used to create unit tests for software written in Java
● JUnit is a representative of the whole family of frameworks for unit
testing called collectively xUnit
● JUnit is in the package
○ junit.framework in JUnit version 3.8 and older
○ org.junit in JUnit version 4.0 and newer
JUnit
JUnit - Java library for creating unit tests
Features of JUnit:
● method is the smallest code snipped being under testing unit,
● test cases
● separation of tests from the code,
● many launch mechanisms
● different reports,
● integration with various programming environments
Test
MyTest
TestCase in JUnit
The base class for all test cases is TestCase, due to the somewhat unfortunate
name, it is often confused with a test case (meanwhile TestCase is a test class that
contains test cases saved as methods; therefore, the test case is a single method, not
a class). This class provides basic functions that help in testing, including default
assertions.
TestResult is a class that stores the results of completed test cases. It is created
and filled with data by subsequent classes TestCase, which are executed.
public class MyClassTest {//from Junit 4.X version we do not inherit from TestCase
// We will test the MyClass class
MyClass tester = new MyClass();
@Test
public void testMultiply() {
assertEquals("10 x 0 must be 0", 0, tester.multiply(10, 0));
assertEquals("0 x 10 must be 0", 0, tester.multiply(0, 10));
assertEquals("0 x 0 must be 0", 0, tester.multiply(0, 0));
}
}
Assertions
Assertions - it is a logical condition which, if not met (false), causes the program
to be interrupted. You may need to add manual import in the class to make the
assertions visible: import static org.junit.Assert.*;
● comparison assertions
assertEquals([message], expected, actual)
checks that the values passed as parameters are equal. For primitive
types, the comparison is performed using the == operator, while for
object types the method equals()is called
● identity assertions
assertSame([message], expected, actual)
assertNotSame([message], expected, actual)
assertSame() (and analogous assertNotSame()) checks the identity
of both parameters, i.e. the operator == in all cases
Assertions cont.
reference assertions null
assertNull([message], reference)
assertNotNull([message], reference)
assertNull() and assertNotNull() they check whether the given
reference points to an object or not
logical assertions
assertTrue([message], condition)
assertFalse([message], condition)
assertTrue() and assertFalse() examine the veracity of the given
conditions
unconditional failure
fail([message])
fail() is an unconditional declaration of false assertions. This method is
useful in special situations where a specific code should never be
executed
assertEquals / assertNotEquals
@Test
public void shouldSumIntegers() {
ArthService service = new ArthService();
int result = service.add(12, 5);
assertEquals(17, result);
}
assertEquals / assertNotEquals
@Test
public void shouldSumIntegers() {
ArthService service = new ArthService();
int result = service.add(12, 5);
assertEquals("Didn’t sum correctly",17,result);
}
assertTrue / assertFalse
@Test
public void shouldRecognizeEvenNumbers() {
boolean isEven1 = service.isEven(12); //even - even
numbers, odd - odd numbers
}
assertTrue / assertFalse
@Test
public void shouldRecognizeEvenNumbers() {
boolean isEven1 = service.isEven(12);
boolean isEven2 = service.isEven(3);
assertTrue("Didn’t recognize even", isEven1);
assertFalse("Didn’t recognize odd", isEven2);
}
granularity of tests
@Test
public void shouldReturnTrueForEvens() {
boolean isEven = service.isEven(12);
assertTrue("Didn’t recognize even", isEven);
}
@Test
public void shouldReturnFalseForOdds() {
boolean isEven = service.isEven(3);
assertFalse("Didn’t recognize odd", isEven);
}
other assertions
assertArrayEquals(expectedTab1,tab); // FAIL
other assertions
assertTrue(condition); // FAIL
assertFalse(condition); // SUCCESS
@Ignore
@Test
public void badTest() {//...}
create
void setUp() @Before
void testOne()
execute
Class RomanNumber void testFive()
void testNineteen()
void testThousand()
remove
void tearDown() @After
@Before - “constructor” of classes type of TestCase
In the case of TestCase class objects, the logical constructor plays any method with
the @Before annotation, and it is the correct place to create an instance of the tested
object.
public class RomanNumberTest{
RomanNumber rn = null;
@Before
public void initialize() {
rn = new RomanNumber(5); //test object
}
}
initialize() with annotation @Before is used to initiate each test case; it is
performed before each of them and is usually used to create a test object of other
objects required to run it.
@Before
@Before
public void setUp() {
service = new ArthService();
}
@Test
public void shouldSumIntegers() {
int result = service.add(12, 5);
assertEquals("Don’t sum correctly",17,result);
}
@After - “destructor” of classes type of TestCase
Method with @After annotation is complementary to the @Before method, i.e. it is used
to restore the state prior to the test. If the @Before method only created objects then no
@After implementation is needed; it only matters if the test case has allocated a
resource that should be released, e.g. a network or database connection, etc. Then this
method should release this resource.
@BeforeClass
public void initializeClass() { //... }
Method with @AfterClass annotation is performed only once in the class after
all test cases have been completed
@AfterClass
public void cleanClass() { //…}
Exceptions testing
In particular, you can test your own methods that throw exceptions in certain situations.
We can check if exceptions are thrown when we expect them.
Running tests @RunWith and @Suit
@Suite.SuiteClasses(...) it is used to group many test classes into one package.
This allows you to run multiple tests at once and have better control over them.
@RunWith(Suite.class)
@Suite.SuiteClasses({JunitTest1.class,JunitTest2.class, JunitTest3.class})
public class AllTests {
}
How to run tests? - Having an open class with @RunWith, in Eclipse we choose from the
menu "Run-> Run As-> JUnit test"
JUnit test results in Eclipse
Features of correct unit tests
● Automation - running tests must be easy.
● Completeness - everything that can fail should be
tested.
● Repeatability - multiple tests give the same results.
● Independence - from the environment and other tests.
● Professionalism - the test code is as important as the
code provided to the customer
● Convention
○ the name of the test method starts with the word:
test, np. testMultiplication()
○ in the name of the testing class we add the word
Test to: MyClassTest
Why is it worth unit testing?