Lab&Assignment10 UnitTesting
Lab&Assignment10 UnitTesting
1. SUBMISSION GUIDELINE
When you want to submit your individual work of in-class tasks for the Case Study,
you have to push your work to your individual GitHub repository, complied with
the naming convention “TeamName-StudentID.StudentName” (e.g.
TKXDPM.KHMT.20231.20192012.HoangNghiaPhu or TKXDPM.VP.20231-
20192122.LuongHongHai).
2. IN-CLASS ASSIGNMENT
In this section, we will get familiar with the software construction process and try
ourselves with unit testing for the Case Study.
The first three subsections would give you an overview about unit testing, test-
driven development, and JUNIT. After that, you will practice them in the last
subsection 2.4. You would need Excel (to design test cases), JUNIT5 (already
included in Eclipse IDE), Oracle JDK 11, and then import the given sample project1.
You are asked to work individually for this section, and then put all your design of
unit test (Excel file, using the file TestPlan.xlsx in the Template folder) to a
directory, namely “UnitTest”, and put the codes in “Programming” directiory. After
that, push your commit to your individual repository before the announced
deadline.
1 https://github.com/trangntt-for-student/AIMS
HANDS-ON LAB GUIDELINES
© SOICT – HUST
ITSS SOFTWARE DEVELOPMENT – IT4945E
2
easier debugging. When a unit test for a module fails, you can be more confident
that the bug is found in that module, rather than anywhere in the program2.
Thus, unit testing is neither suitable for testing complicated user interface nor the
interaction among great modules/subsystems.
In the article TDD - What it is and what it is not4, Andrea Koutifaris describes this
cycle:
2http://web.mit.edu/6.031/www/sp17/classes/03-testing/#automated_unit_testing_with_junit
3https://www.ibm.com/garage/method/practices/code/practice_test_driven_development/
4https://medium.freecodecamp.org/test-driven-development-what-it-is-and-what-it-is-not-
41fa6bca02a2
HANDS-ON LAB GUIDELINES
© SOICT – HUST
ITSS SOFTWARE DEVELOPMENT – IT4945E
3
• Red phase: You write an automated test for a behavior that you're about to
implement. Based on the user requirement, you decide how you can write a
test that uses a piece of code as if it were implemented. This is a good
opportunity to think about the externals of the code, without getting
distracted by actually filling in the implementation. Think about what the
interface should look like? What behaviours should a caller of that interface
expect? Is the interface clean and consumable?
• Green phase: You write production code, but only enough production code
to pass the test. You don't write algorithms, and you don't think about
performance. You can duplicate code and even violate best practices. By
addressing the simplest tasks, your code is less prone to errors and you
avoid winding up with a mix of code: some tested (your minimalist
functions) and some untested (other parts that are needed later).
• Refactor phase: You change the code so that it becomes better. At a
minimum, you remove code duplication. Removing duplication generally
leads to abstraction. Your specific code become more general. The unit tests
provide a safety net which supports the refactoring, because they make sure
that the behavior stays the same and nothing breaks. In general, tests should
not need to be changed during the refactor stage.
TDD drives the code development, and every line of code has an associated test
case, so unit testing is integrated into the practice. Unit testing is repeatedly done
on the code until each unit functions per the requirements, eliminating the need
for you to write more unit test cases.
You can get started with TDD by following these steps:
1. Think about the behaviors that your implementation requires. Select a
behavior to implement.
2. Write a test that validates the behavior. The test case must fail.
3. Add only enough code to make the new test case and all previous test cases
pass.
4. Refactor the code to eliminate duplicate code, if necessary.
5. Select the next requirement and repeat steps 1 - 4.
5 http://web.mit.edu/6.031/www/sp17/classes/03-testing/#automated_unit_testing_with_junit
HANDS-ON LAB GUIDELINES
© SOICT – HUST
ITSS SOFTWARE DEVELOPMENT – IT4945E
4
A unit test method typically contains one or more calls to the module being tested,
and then checks the results using assertion methods like assertEquals, assertTrue,
and assertFalse.
For example, the tests we chose for Math.max() above might look like this when
implemented for JUnit:
@Test
public void testALessThanB() {
assertEquals(2, Math.max(1, 2));
}
@Test
public void testBothEqual() {
assertEquals(9, Math.max(9, 9));
}
@Test
public void testAGreaterThanB() {
assertEquals(-5. Math.max(-5, -6));
}
Note that the order of the parameters to assertEquals is important. The first
parameter should be the expected result, usually a constant, that the test wants to
see. The second parameter is the actual result, what the code actually does. If you
switch them around, then JUnit will produce a confusing error message when the
test fails. All the assertions supported by JUnit follow this order consistently:
expected first, actual second.
If an assertion in a test method fails, then that test method returns immediately,
and JUnit records a failure for that test. A test class can contain any number of
@Test methods, which are run independently when you run the test class with
JUnit. Even if one test method fails, the others will still be run.
2.3.2. Documenting Your Testing Strategy6
Let consider a function that reverses the end of a string.
/**
* Reverses the end of a string.
*
* For example:
* reverseEnd("Hello, world", 5)
* returns "Hellodlrow ,"
*
6 http://web.mit.edu/6.031/www/sp17/classes/03-testing/#automated_unit_testing_with_junit
HANDS-ON LAB GUIDELINES
© SOICT – HUST
ITSS SOFTWARE DEVELOPMENT – IT4945E
5
For example, at the top of the class, we can document the testing strategy we
worked on in the partitioning exercises above. The strategy also addresses some
boundary values we did not consider before.
/*
* Testing strategy
*
* Partition the inputs as follows:
* text.length(): 0, 1, > 1
* start: 0, 1, 1 < start < text.length(),
* text.length() - 1, text.length()
* text.length()-start: 0, 1, even > 1, odd > 1
*
* Include even- and odd-length reversals because
* only odd has a middle element that doesn't move.
*
* Exhaustive Cartesian coverage of partitions.
*/
Each test method should also need a comment above it saying how its test case was
chosen, i.e. which parts of the partitions it covers:
// covers test.length() = 0,
// start = 0 = text.length(),
// text.length()-start = 0
@Test public void testEmpty() {
assertEquals("", reverseEnd("", 0));
}
JUnit 5 Description
The annotated (static) method will be executed once before any @Test method
@BeforeAll in the current class.
The annotated method will be executed before each @Test method in the
@BeforeEach current class.
The annotated method will be executed after each @Test method in the current
@AfterEach class.
The annotated (static) method will be executed once after all @Test methods in
@AfterAll the current class.
The annotated method will not be executed (it will be skipped), but reported as
@Disabled such.
Figure 2-Important Annotations in JUNIT5
# Parameter Conditions
7 https://developer.ibm.com/tutorials/j-introducing-junit5-part1-jupiter-api/
HANDS-ON LAB GUIDELINES
© SOICT – HUST
ITSS SOFTWARE DEVELOPMENT – IT4945E
7
# Parameter Conditions
3 address - Only letters (a-z and A-Z) or digits (0-9) or slashes are
allowed
- Maximum of 100 characters
- Must not null
Obviously, if we run the test now, the test will be failed since we have not
implemented anything yet.
We can put a list of input-expected output pairs to test at once by using annotations
@Parameterized and @CsvSource. After that, run the test again.
You can see that there is a failed test case: the one with the input-output pair
"1234567890,false". We need to go back to the method and add the validation
codes for the phone number which must start with 0. At last, we have all passed
test cases.
In another hand, these three test cases could make a test suite. A test suite is a
collection of test cases related to the same test work.
Right click on the project -> New -> Test Suite
Add all classes that we need to test in the test suite into class AllTest and then run.
2.5. ASSIGNMENT
In this part, you are asked to apply TDD to implement your design for the
method calculateShippingFee in the PlaceOrderController.