0

I'm currently trying to add some JUnit tests to my pathdrawing system in order to check if the calculations are right...
Currently I have:

Class to Test(MapRouteDrawer.java):

protected static double[] getCoords(PolynomialSplineFunction curve, double[] index) {
  final double detailLevel = 1.0;//Tweak this value in order to achieve good rendering results
  final double defaultCoordSize = index[index.length - 1];
  final double[] coords = new double[(int)Math.round(detailLevel * defaultCoordSize) + 1];
  final double stepSize = curve.getKnots()[curve.getKnots().length - 1] / coords.length;
  double curValue = 0;
  for (int i = 0; i < coords.length; i ++) {
    coords[i] = curve.value(curValue);//gets y value of specified x value
    curValue += stepSize;
  }
  return coords;
}

protected static double[] getIndex(Point[] points) {
  final double[] index = new double[points.length];
  if(index.length > 0){
    index[0] = 0;
  }
  for (int i = 1; i < points.length; i++) {
    index[i] = index[i - 1] + Math.sqrt(points[i - 1].distance(points[i]));
  }
  return index;
}

TestClass:

private Point[] dummyPoints = new Point[]{new Point(0,0), new Point(100,0), new Point(0,100)};//Some Points for Testing
//This returns a so called index - the squareroot distance between addedn on top of each other
private double[] dummyIndex = MapRouteDrawer.getIndex(dummyPoints);

@Test
public void testCurve(){
  final double[] testYValues = new double[]{20, 40, 90};
  final PolynomialSplineFunction testFunction = new SplineInterpolator().interpolate(dummyIndex, testYValues);//get a Spline-Interpolated curve
  final double[] coords = MapRouteDrawer.getCoords(testFunction, dummyIndex);//Calls the function to test
  final double factor = testFunction.getKnots()[testFunction.getKnots().length - 1] / coords.length;
  assertEquals(testYValues[0] * factor, coords[(int)Math.round(dummyIndex[0])], 1);//Check if the coordinates are equal
  assertEquals(testYValues[1] * factor, coords[(int)Math.round(dummyIndex[1])], 1);
  assertEquals(testYValues[2] * factor, coords[(int)Math.round(dummyIndex[2])], 1);
}

This is working fine, but if you are familiar with JUnit you may notice the delta of 1 which is neccesary in order for this Test to work...
What I'm trying to achieve is this:

@Test
public void testCurve(){
  final double[] testYValues = new double[]{20, 40, 90};
  final PolynomialSplineFunction testFunction = new SplineInterpolator().interpolate(dummyIndex, testYValues);//get a Spline-Interpolated curve
  final double[] coords = MapRouteDrawer.getCoords(testFunction, dummyIndex);//Calls the function to test
  final double factor;//Unknown... should be dynamic, so it does not matter which detail level I chose
  assertEquals(testYValues[0], coords[(int)Math.round(dummyIndex[0])] * factor, 0);//Check if the coordinates are equal
  assertEquals(testYValues[1], coords[(int)Math.round(dummyIndex[1])] * factor, 0);//e.g. coords[(int)Math.round(dummyIndex[0])] * factor == 20 etc.
  assertEquals(testYValues[2], coords[(int)Math.round(dummyIndex[2])] * factor, 0);
}

So that the first value in assertEquals() is 20, 40, 90 etc. and not a weird 21.39587576787686 (or similar) number and the delta is 0 (or 0.01 if there is no other way) and not 1 which I'm currently using

Because I'm using a detail level in my getCoords() method, which should be able to be adjusted without having to change the test, there is a need to make the "factor" in my test related to the coords-size.

How would I calculate the factor in order for the Test to succeed?
Any help is would be very much appreciated

RoiEX
  • 1,186
  • 1
  • 10
  • 37
  • You access an array with a double that is rounded and then cast to an int as an index?!? Now I'd really like to know how you ended up doing this :) – yeoman May 30 '16 at 13:55
  • Side note: in the long run, your tests should be as easy to read as possible. You want others to immediately understand what they are about. One generic hint to get there: try to have **one** assert per test method. It is better to have 10 methods name like testGetCoordsWithBla,testGetCoordsWithBlub, testGetCoordsWithWhatever) ... than having multiple asserts in one method. If that one method fails, you first have to figure which of the statements is causing trouble, and so on. Besides: considered to use **assertThat** and writing a customer matcher? – GhostCat May 30 '16 at 13:56
  • Well, I sometimes have asserts in a loop, going through millions of predefined or random values. The trick is to have verbose and helpful enough output that shows you for what input values the test failed. – yeoman May 30 '16 at 13:57
  • @yeoman If that is the most efficient way for you to write down your tests; fair enough - it is your code. All I am saying: there are certain best practices that recommend to do things differently (and for good reasons). – GhostCat May 30 '16 at 13:59
  • @yeoman well this index is basically used as average value between the points, to avoid round mistakes by the JVM - it's working since thats what the method being tested is doing as well. – RoiEX May 30 '16 at 14:01
  • @Jägermeister You are probably right. But since this value is an array, in my opinions it makes sense to test if the "initial 3 points" are still present in one single test, and not to have three seperate test for this single task... – RoiEX May 30 '16 at 14:03
  • @RoiEX Sure. But still: consider at least renaming that method. testCurve() doesn't really tell what that method is about to test, does it?! – GhostCat May 30 '16 at 14:25
  • @Jägermeister I'll do eventually - let's see if someone has an answer for this first... – RoiEX May 30 '16 at 17:07
  • @Jägermeister the word "best practices" sometimes makes me shudder... -.- Do you really suggest 10 million methods for ten million test values? – yeoman May 31 '16 at 07:42
  • I did not say that you absolutely must break up loops and put them into individual methods.To the contrary, if you have so many values to check for; I would be looking into more sophisticated concepts - like quickcheck, or at least *Parametrized* runners). All I am saying is: **looking at the given example** many people find it helpful to **not** do it this way. Again, if your style works better for **you** then there is no need to change anything. But there is a valid reason for best practices to exist. And you see, it is not like I invented that, as said: it is a best **common** practice. – GhostCat May 31 '16 at 07:51

0 Answers0