0

I have a simple faulty method that I would like to write a JUnit statement to test Here is the code:

public static ArrayList union(ArrayList a, ArrayList b) {
    ArrayList d;        

    int randNum = (int) Math.random();

    // if random is dividable by 2 then a is return else b will.
    if (randNum % 2 == 0)
    {
        return a;
    }
    else
    {
        return b;
    }

}

Here is the problem casting Math.random() is not going to produce an integer random number. So, when the method is called it is going to return the array list a. I would like to write a test case that covers this statement and make it fail to show that It is not reaching b.

Currently I have this test case:

@Test
public void testUnion_2() throws Exception {
    ArrayList a = new ArrayList();
    ArrayList b = new ArrayList();

    ArrayList result = SectionOne.union(a, b);

    // add additional test code here
    assertNotNull(result);
    assertEquals(0, result.size());
}

Thanks I really appreciate the help.

NamshubWriter
  • 23,549
  • 2
  • 41
  • 59
SpeedDemon
  • 11
  • 1
  • 2
  • 2
    Use [Random.nextInt()](http://stackoverflow.com/questions/738629/math-random-versus-random-nextintint) – SubSevn Apr 23 '14 at 15:53
  • Sure, for a correction. But can't I assert or have access to state that the else will not be return any time this method is called. – SpeedDemon Apr 23 '14 at 15:57
  • 1
    The question is rather how to unit-test this method than to fix it... – Gyro Gearless Apr 23 '14 at 15:57
  • If you want to do this the "right" way then you want to inject a reference to a random number generator (which in this case, wouldn't be random). – SubSevn Apr 23 '14 at 16:03
  • Yes Gyro, I want to unit test the method to make it return array list b. Of course, that is not possible because of the way randNum is defined any idea how ? – SpeedDemon Apr 23 '14 at 16:03

4 Answers4

1

You should perhaps call the method under test say 1000 or 10000 times and check that you get a about 50% of the time.

Gyro Gearless
  • 5,131
  • 3
  • 18
  • 14
1

You should consider rewriting the method to be more testable but the benefits of testing this code are small compared to the cost of maintaining the code and the tests.

I suggest creating a version of the method where you pass in the Random instance:

static <E> List<E> pickOneAtRandom(List<E> a, List<E> b, Random random) {
  if (random.nextInt(2) == 0) {
     return a;
  }
  return b;
}


public static <E> List<E> pickOneAtRandom(List<E> a, List<E> b) {
  return pickOneAtRandom(a, b, new Random());
}

Then you could test the first method with a mocking framework or by passing in a Random instance with a hard-coded seed.

(note I renamed the method; union to me would imply somehow merging the two lists)

You may decide to make the first method public (perhaps the caller wants to use SecureRandom).

There are a few problems with this approach:

  1. if you use a mock, you end up hard-coding the implementation in your test
  2. if you test with a Random instance with a constant seed, it can lead to a test that can break due to simple changes in the implementation.

Other people suggested running the test multiple times. There are a few problems with having a test call the method multiple times:

  1. it can slow down your test run
  2. the test could only prove that it was likely that the first list was selected 50% of the time

Personally, I think this code is simple enough that it doesn't need a test.

NamshubWriter
  • 23,549
  • 2
  • 41
  • 59
0

Call the method 100 times and count resulting a and b. Since you use random, it is unlikely that your test ends up with only a or b. So check the a and the b counter to be greater than 0.

Hannes
  • 2,018
  • 25
  • 32
0

You could alter the behaviour of a call to Math.random() by using a tool like PowerMock, which supports mocking java system classes in newer versions.

If you do this, you can test the rest of your method's code. But I think the point is more to prove that Math.random() does never deliver a result that fulfills "randNum % 2 != 0".

mdo
  • 6,961
  • 3
  • 24
  • 26