Assignment 11: Unit Testing

Release date: Thursday, 25.06.14 - Due date: Monday, 29.06.14, 11:59

I published two sample exams from previous years for your preparation in: https://svn.iai.uni-bonn.de/repos/IAI_Software/se/oosc2015/slides/

Task 43: Test Driven Development, Roman Numerals

9 points + [4 points]

In the lecture we started to implement RomanNumerals again. This time we used the TDD approach. Continue with this implementation for 30 minutes. As you know, there are already some sample solutions. But, this time you have to strictly follow the TDD steps:

  1. Red: Implement a test case, that describes expected functionality but fails. Keep this step as small as possible.1)
  2. Green: Make the test green by extending the current implementation as little as possible.2)
  3. Gold: Beautify your implementation, including the test code.3)
  4. Repeat.4)

After 30 minutes you are done, even if the functionality is not complete. Start with the code in A11T43_TestDrivenRomans. Copying from the existing implementation is only allowed, when it still keeps the step 1 and 2 as small as possible. We will only evaluate, whether you followed the TDD steps strictly and whether your increments were correct.

Please prove to us, that you followed the approach. Commit manually after each step, so your work-flow becomes:

  1. Red: Implement a test case and commit it.
  2. Green: Improve the implementation and commit it.
  3. Gold: Beautify test and implementation and commit them.
  4. Repeat.

Optional Discussion:

Thoroughly discuss the quality of your test with respect to White-Box and Black-Box criteria.


Task 44: Black Box Testing, Triangles

12 points

Imagine you have to test the class Triangle, whose source code you do not know. The class's only public method of interest is Triangle.contains(Triangle t) and it is supposed to check if the triangle contains some other triangle t. For example the green triangle on the right contains the red one, i.e. greenTriangle.contains(redTriangle) should be true. On the other hand the red doesn't contain the green one, i.e. redTriangle.contains(greenTriangle) should be false.

a) Create a test plan:

  • Find and write down criteria for equivalence classes of test cases for a black box test of this method. You might want to draw some images to illustrate your answers.
  • Write down a short justification why your criteria are good.
  • Pick some representatives for each of the equivalence classes and write some tests verifying your expectations for this example.

b) Debunk the faulty implementations

Your company decided that it is too difficult5) to develop the contains(..) method within the company. So they announced that they want to buy an implementation. In response they got 17 implementations, but they doubt that many of them are correct. You got the job to find the implementation that is working. Of course you didn't get the source code, but you are a smart tester. Write some tests to find the implementation your company should actually buy. If you did the optional step, you can use the tests that your produced. Here is your guide to the source code:

  • You find the code in the project A11T44_Triangles
    • The folder cls contains the implementations Triangle00 till Triangle16.
    • In the folder tst you find the class geometry.TriangleTest. This test exercises all the implementations using the same test methods for each.6)
  • Run the test.
    • You see some tests failing for the class Triangle14 and Triangle16.
    • Review the test methods and decide whether they make sense. If they do, Triangle14 and Triangle16 are out.
  • The test method ifOneTriangleIsVeryLargeAndTheOtherVerySmall is annotated with @Ignore and therefore ignored.
    • Is the test method correct? If yes: Remove the @Ignore annotation and run the tests again.
  • Implement some of your test cases from your plan. That is: Pick one to three representatives for each equivalence class and decide about the expected result. Create the triangles7) and add assertions for the expected results.
    • Run your tests and find out which implementation are wrong.
    • We heard that some implementations have only minor errors, so finding the single correct implementation is probably quite hard.
    • You should be able to reduce the number of implementations significantly.
  • Have fun with this exercise :-)

Task 45: White Box Testing, cloud BAKERY 2100 Supplies

10 points

Given is the following class Supplies that simulates the supplies in a station of our cloud BAKERY 2100.

The Model of the Supplies at a cloud BAKERY 2100 Station

public class Supplies {
 
    private Map<Ingredient, Quantity> supplies = new HashMap<>();
    private Map<Long, Map<Ingredient, Quantity>> reservations = new HashMap<>();
 
    private Quantity availableQuantity(Ingredient ingredient) {
        // Calculates the available amount of the ingredient
        // based on supplies and reservations.
    }
 
    /* For tests only! Visible in the package only. */
    void setState(Map<Ingredient, Quantity> supplies, Map<Long, Map<Ingredient, Quantity>> reservations) {
        this.supplies = supplies;
        this.reservations = reservations;
   }
 
    public void reserve(Ingredient ingredient, Quantity requested, long orderId)
            throws NotEnoughIngredientsException {                                // start
 
        Quantity available = availableQuantity(ingredient);                       //  1
        if (available.compareTo(requested) < 0) {                                 //  2
            throw new NotEnoughIngredientsException("Not enough of ingredient "   //  3
                    + ingredient + ". Requested=" + requested + ", available="
                    + available);
        }
        Map<Ingredient, Quantity> reservation = reservations.get(orderId);        //  4
        if (reservation == null) {                                                //  5
            reservation = new HashMap<>();                                        //  6
            reservations.put(orderId, reservation);                               //  7
        }
        Quantity reservedQuantity = reservation.get(ingredient);                  //  8
        if (reservedQuantity == null) {                                           //  9
            reservation.put(ingredient, requested);                               // 10
        } else {
            reservedQuantity.add(requested);                                      // 11
        }
    }                                                                             // end
 
    // ... more methods ...
}
  1. Draw a control flow graph for the reserve method.
  2. With the setState method tests have full control of the fields supplies and reservations. So, we can consider the state of these two fields as part of the input data. Give an example input data that achieves high statement coverage and write down the execution path. (E.g., if we want to reserve salt, but there is no salt an exception is thrown. You might haven written “supplies={sugar → 5kg, flour → 10kg, milk → 1l, wine → 3l}, reservations={123 → {milk → 200ml}, 124 → {wine → 300ml}}, ingredient=salt, requested=5g, orderId=200; execution path = start-1-2-3-end”)
  3. Do we always have full branch coverage as soon as we have full statement coverage?
    • If yes, complete your example so that we have full statement coverage and therefore full branch coverage.
    • If no, complete your example so that we have full statement coverage but not full branch coverage.
  4. How many paths does this method have? Give an input example for each path.
1) Remember: Our first test was assertEquals(“I”, roman(1));.
2) Remember: Our first implementation was return “I”;.
3) You should give your tests meaningful names.
4) For 30 minutes or until you are done.
5) They didn't listen to you :-(
6) There is quite some JUnit 4 and Java Reflection Magic behind the mechanism to run the test for each of the implementations. You don't need to understand that. The only thing to remember is, that you should use the createTriangle(..) method to create triangles. Don't use the constructors directly!
7) Remember to use the createTriangle(..) method to create triangles!
Last modified: 2017/08/29 23:30
 
*