IllegalStateException no last call on a mock available

I'm trying to use EasyMock to test that a method runs a specific number of times but I keep getting an IllegalStateException error and I don't understand why. I'm new to EasyMock and JUnit and not very familiar with how to use them so I'm not sure what I'm doing wrong.

My code is:

FileOutputStream mockWriter;
Numbers mockByte;
@Test
public void testNumbers() throws IOException{   
    mockWriter = createMock(FileOutputStream.class);
    mockByte = new Numbers(mockWriter);
    mockByte.initByte();
    expect(mockByte.generate()).times(10000);
    replay(mockWriter);
}

And these are the methods initByte and generate from my Numbers class:

public void initByte() throws IOException{  
    File outFile = new File("NumbersOutput.txt");
    FileOutputStream f = new FileOutputStream(outFile);
    for(int i = 0; i < 10000; i++){
        int b = generate();
        f.write(b);
    }   
    f.flush();
    f.close();  
}

public int generate(){
    return rand.nextInt(100001);
}
Jon Skeet
people
quotationmark

The error you're getting is because nothing's calling anything on your mock.

Contrary to your naming, mockByte doesn't refer to a mock at all, so using it in an expect call like this is not going to help you. You should be expecting calls on mockWriter if anything.

However, it's not clear why you're using a mock for a stream at all, nor what the OutputStream in the Numbers constructor is used for. Your initByte() method doesn't use any state within the object other than rand. Even when that's fixed, it would probably be simplest just to use a ByteArrayOutputStream... make your API talk in terms of OutputStream instead of FileOutputStream, and it'll be much easier to test.

I suspect you should:

  • Remove the construction of a new FileOutputStream from the initByte method, instead writing to the stream you accept in the Numbers constructor
  • If your constructor parameter type is FileOutputStream, change it to OutputStream to make it cleaner and easier to test
  • Create a ByteArrayOutputStream in your test - you don't need mocking at all. You can then get all the bytes that have been written, and check them for whatever you want.
  • Think carefully about what you expect f.write(b) to do. It's only going to write a single byte, so the top 24 bits of your random number are going to be ignored. At that point, why are you choosing a number in the range [0, 10000] anyway?

people

See more on this question at Stackoverflow