Nathan Reese
Nathan Reese

Reputation: 311

EasyMock and modifing a mutable method parameter

How does one use EasyMock to modify a mocked method's mutable method parameter?

For example, I have class that uses a BlockingQueue. I want to mock the BlockingQueue member for unit testing. My class calls the method queue.drainTo(Collection c). Calling this method removes elements from the queue and adds them to the collection. How would I mock this behavior using EasyMock? Examples would be great.

Upvotes: 6

Views: 5829

Answers (2)

NamshubWriter
NamshubWriter

Reputation: 24326

You can use andAnswer and getCurrentArguments:

public void testDrainToQueue() {
  BlockingQueue<Foo> queue = EasyMock.createMock(BlockingQueue.class);
  EasyMock.expect(queue.drainTo(EasyMock.isA(List.class)))
      .andAnswer(new IAnswer<Integer>() {
        public Integer answer() {
          ((List) EasyMock.getCurrentArguments()[0]).add(new Foo(123));
          return 1; // 1 element drained
        }
      });
  EasyMock.replay(queue);
  ...
}

It sometimes helps to extract a helper class or method:

private static IAnswer<Integer> fakeDrainReturning(final List drainedElements) {
  return new IAnswer<Integer() {
    @Override public Integer answer() {
      ((List) EasyMock.getCurrentArguments()[0]).addAll(drainedElements);
      return drainedElements.size();
    }
  };
}

Then you can do:

List<Foo> drainedElements = Arrays.asList(new Foo(123), new Foo(42));
EasyMock.expect(queue.drainTo(EasyMock.isA(List.class)))
    .andAnswer(fakeDrainReturning(drainedElements));

It might be better to use a real BlockingQueue and find a way to insert the desired value into the queue before the method that you expect to remove data from the queue.

Upvotes: 13

bwawok
bwawok

Reputation: 15377

hard to tell exactly what your code looks like. Could help you better if I knew the code you want to test.. but assuming your code you want to test looks like this:

private BlockingQueue<String> queue;
private List<String>  myList = new ArrayList<String> ():

private void setBlockingQueue( BlockingQueue<String>  queue ) { 
    this.queue = queue;
}

public List<String> getMyList() {
    return myList;
}

public void setMyList( List<String> myList) {
    this.myList = myList;
}

public void doWork() {
    System.out.println("blah");
    queue.drainTo( myList );
}

A test would be

public void testDoWork() {
    List<String> stuffToDrain = new ArrayList<String>();
    stuffToDrain.add( "foo" );
    stuffToDrain.add( "bar" );
    myTestingClass.setMyList( stuffToTrain );


    BlockingQueue<String> queue = EasyMock.createMock( BlockingQueue.class  );
    myTestingClass.setBlockingQueue( queue );
    queue.drainTo( stuffToDrain );
    EasyMock.replay( queue );
    myTestingClass.doWork();
    EasyMock.verify( queue );



}

Sorry if that isn't right, but really hard to suggest a test for code that I can't see...

Edit - we can't really assert that the mutable param gets changed becuase of how we are using the mock. All we can do is assert that the drainTo method gets called. If drainTo does what we want to do would have to be tested elsewhere.. i.e. in the tests of BlockingQueue.class

Edit 2 - we can be more specific about what list we expect the method to get called with.

Upvotes: 0

Related Questions