Home CPSC 330

More Testing

JUnit Messages

We can add textual messages to asserts in JUnit in order to make them more helpful. Each of the assert methods has an optional first String parameter printed if the assert fails:


import org.junit.*;

public class AdderTest { @Test public void testAdd() {
  // test some cases
  Assert.assertEquals("Addition test 1", Adder.add(12, 19), 31);
  Assert.assertEquals("Addition test 2", Adder.add(0, -19), -19);
  Assert.assertEquals("Addition test 3", Adder.add(190, 0), 190);
  Assert.assertEquals("Addition test 4", Adder.add(-10, 20), 10); }
}

Testing for Exceptions

In the Line class we saw in lab, the getSlope method looks like this:


public double getSlope() {
  // avoid dividing by zero
  if(x1 == x0) {
    throw new ArithmeticException();
  }

  return (y1 - y0) / (x1 - x0);
}

If we want to enforce the fact that this method should throw the exception in this case, we can go ahead and do so in our test:


@Test public void testSlope() {
  Line vertical = new Line(5.0, 5.0, 5.0, 10.0);

  try {
    vertical.getSlope();

    // if we got here, there was no exception
    Assert.fail("Should throw exception for slope of vertical lines!");

  } catch(ArithmeticException e) {
    // do nothing
  }

}

Using Mock Objects

Sometimes to test a unit, we need input from some other part of a system:

It may be impractical or impossible to test all of the different inputs that may come from these sources:

These issues can be dealt with using mock objects which provide mock data for testing purposes.

For example, if we have the following code that provides GPS coordinates in an Android application:


class Coords {
  public Coords(double lat, double lon) {
    lattitude = lat;
    longitude  = lon;
  }

  public double getLattitude() {
    return lattitude;
  }

  public double getLongitude() {
    return longitude;
  }

  private double lattitude, longitude;
}

class GPS {
  public Coords getLocation() {
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    String bestProvider = locationManager.getBestProvider(criteria, false);
    Location location = locationManager.getLastKnownLocation(bestProvider);
    return new Coords(location.getLattitude(), location.getLongitude());
  }
}

We may want to be able to test this with different locations. This can be done by making the GPS class an interface and providing mock implementations of it:


interface GPS {
  public Coords getLocation();
}


class RealGPS implements GPS {
  public Coords getLocation() {
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    String bestProvider = locationManager.getBestProvider(criteria, false);
    Location location = locationManager.getLastKnownLocation(bestProvider);
    return new Coords(location.getLattitude(), location.getLongitude());
  }
}

// a mock GPS object that provides coordinates from around Paris, France
class FakeGPS implements GPS {
  public FakeGPS() {
    test_data = new Coords[10];
    i = 0;
    test_data[0] = new Coords(48.862, 2.807);, 
    test_data[1] = new Coords(48.901, 2.683);, 
    test_data[2] = new Coords(48.833, 1.983);, 
    test_data[3] = new Coords(49.268, 2.141);, 
    test_data[4] = new Coords(48.561, 2.288);, 
    test_data[5] = new Coords(48.779, 2.105);, 
    test_data[6] = new Coords(48.960, 1.835);, 
    test_data[7] = new Coords(49.037, 2.371);, 
    test_data[8] = new Coords(48.324, 2.435);, 
    test_data[9] = new Coords(49.185, 1.916);, 
  }

  public Coords getLocation() {
    Coords here = test_data[i];
    i++;
    if(i >= 10) {
      i = 0;
    }
    return here;
  }

  private Coords[] test_data;
  private int i;
}

Now we can write our code to use the GPS interface. When actually running our code, we can provide the real implementation. Wehntesting, we can provide the mock object.


Test-Driven Development

The idea behind test-driven development is that, instead of testing code after we write it, we write the tests first.

Once we have the tests, we then write code that fulfills the tests. This practice has become more popular in recent years.

Benefits of test-driven development include:

Copyright © 2018 Ian Finlayson | Licensed under a Creative Commons Attribution 4.0 International License.