SDA SE Wiki

Software Engineering for Smart Data Analytics & Smart Data Analytics for Software Engineering

User Tools

Site Tools


Assignment 12: Testing and Refactoring

Due at Wednesday, July 13th, 23:59
This is the last assignment! The deadline is before the second exam rehearsal. The mandatory part is only 6 points. The additional optional 12 points might be some fun. We strongly recommend at least to work a bit on them to repeat the content of the lecture.

Task 42: White-Box Testing

3 points

We put a small Project called A12T42_DiscountTrouble in your repository. It consists of an Item class with static methods for calculating the sum of the item's prices (for example bikes), including discounts.

You can find a Junit Test for this class, too.

  • What kinds of coverage does this test achieve?
  • Find all paths through the code and implement a JUnit assertion for each one.1) You can reuse the existing tests.

Task 43: Black-Box Testing

3 points + 4 optional points

Theory

  • 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.
  • 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.

Praxis (optional but fun)

Your company decided that it is too difficult 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 have your plan for equivalence classes. Pick some representatives for each of the equivalence classes and write some tests to find the implementation your company should actually buy. Here is your guide to the source code:

  • Check out the project A12T43_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.2)
  • Run the test.
    • You see some tests failing for the class Triangle14 and Triangle16. (As on the image on the right.)
    • 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 “one triangle is very large and the other is very small” a meaningful equivalence class?
    • 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 triangles3) 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 44: Refactoring (optional)

6 + 2 optional points

We have an implementation of a class Rectangle that stores its coordinates in two instances of the class Interval, one for the horizontal and one for the vertical extension of the Rectangle.

  1. Review the code below. Give us six ideas how to improve it. If you can name a bad smell somewhere, do it. Which refactorings would you apply? We won't count the suggestion to introduce getter-methods. (Maybe you understand later why (see 3)).
  2. Give us for four cases the code that we would get after your refactoring.
  3. Optional! Reviewing your code after executing the refactorings, could you imagine why we suggest being reluctant concerning the introduction of getter-methods?

You can find the source code for this task (with a JUnit-test) as well in your repository in the project A12T44_Refactoring.

View.java

package gui;
import model.Rectangle;

public class View {
  public Rectangle rectangle;
  public void redraw() {
    System.out.println(rectangle);
  }
}

Rectangle.java

package model;
import static java.lang.Math.*;
import gui.View;

public class Rectangle {

  private Interval horizontal;
  private Interval vertical;
  private View view;

  public Rectangle(View view, int startX, int startY, int endX, int endY) {
    if ((startX > endX) || (startY > endY))
      throw new IllegalArgumentException("Parameters in wrong order.");
    this.horizontal = new Interval(startX, endX);
    this.vertical = new Interval(startY, endY);
    this.view = view; view.rectangle = this;
  }

  /**
   * Create an empty Rectangle with no location.
   */
  public Rectangle(View view) {
    this.horizontal = null;
    this.vertical = null;
    this.view = view; view.rectangle = this;
  }
 
  public Vertex getCenter() {
    if (horizontal == null)
      return null;
    return new Vertex((horizontal.start + horizontal.end) / 2,
        (vertical.start + vertical.end) / 2);
  }

  public boolean contains(Rectangle parameter) {
    if (parameter.horizontal == null)
      return false;
    if (horizontal == null)
      return false;
    // check whether the horizontal interval
    // contains the horizontal interval
    // in the other rectangle
    // AND
    // check whether the vertical interval
    // contains the vertical interval
    // in the other rectangle
    return ((horizontal.start <= parameter.horizontal.start) 
      && (parameter.horizontal.end <= horizontal.end))
      && ((vertical.start <= parameter.vertical.start) 
      && (parameter.vertical.end <= vertical.end));
  }

  /**
   * Enlarge the Rectangle just enough so that it contains the other
   * Rectangle. If the Rectangle was empty it gets the same extension
   * as the other Rectangle.
   */
  public void accommodate(Rectangle other) {
    if ((other == null) || (other.horizontal == null))
      return;
    if (horizontal == null) {
      horizontal = new Interval(other.horizontal);
      vertical = new Interval(other.vertical);
      return;
    }
    horizontal.start = min(other.horizontal.start, horizontal.start);
    horizontal.end = max(other.horizontal.end, horizontal.end);
    vertical.start = min(other.vertical.start, vertical.start);
    vertical.end = max(other.vertical.end, vertical.end);
    view.redraw();	
  }

  public boolean equals(Object obj) {
    if (!(obj instanceof Rectangle))
      return false;
    Rectangle other = (Rectangle) obj;
    if (horizontal == null)
      return (other.horizontal == null);
    return (horizontal.equals(other.horizontal))
        && (vertical.equals(other.vertical));
  }

  public String toString() {
    return "Rectangle(" + horizontal + " x " + vertical + ")";
  }
}

The automated refactorings in Eclipse are more effective if you use some tricks:

  • Before extracting a method extract those expression you want to become parameters into local variables.
  • Before moving a part of a method to another class, you should extract this part into an own method in the current class.
  • If you need more tips: Ask on the mailing list! :-)

1)
thus achieving full path coverage
2)
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!
3)
Remember to use the createTriangle(..) method to create triangles!
teaching/lectures/oosc/2010/assignment_12.txt · Last modified: 2018/05/09 01:59 (external edit)

SEWiki, © 2020