EasyMock: Void Methods

倖福魔咒の 提交于 2019-12-17 15:26:31

问题


I have a method that returns void in a class that is a dependency of the class I want to test.

This class is huge and I'm only using this single method from it. I need to replace the implementation of this method for the test as I want it to do something different and I need to be able to access the parameters this method receives.

I cannot find a way of doing this in EasyMock. I think I know how to do it with Mockito by using doAnswer but I don't want to add another library unless absolutely necessary.


回答1:


If I understand what you want to do correctly, you should be able to use andAnswer():

mockObject.someMethod(eq(param1), eq(param2));
expectLastCall().andAnswer(new IAnswer() {
    public Object answer() {
        //supply your mock implementation here...
        SomeClass arg1 = (SomeClass) getCurrentArguments()[0];
        AnotherClass arg2 = (AnotherClass) getCurrentArguments()[1];
        arg1.doSomething(blah);
        //return the value to be returned by the method (null for void)
        return null;
    }
});

The EasyMock User Guide explains:

Creating Return Values or Exceptions

Sometimes we would like our mock object to return a value or throw an exception that is created at the time of the actual call. Since EasyMock 2.2, the object returned by expectLastCall() and expect(T value) provides the method andAnswer(IAnswer answer) which allows [you] to specify an implementation of the interface IAnswer that is used to create the return value or exception.

Inside an IAnswer callback, the arguments passed to the mock call are available via EasyMock.getCurrentArguments(). If you use these, refactorings like reordering parameters may break your tests. You have been warned.




回答2:


If you just call the void method for each time you're expecting it to be invoked and then invoke EasyMock.expectLastCall() prior to calling replay(), Easymock will “remember” each invocation.

So I don’t think you need to explicitly call expect() (other than lastCall) since you’re not expecting anything from a void method, except its invocation.

Thanks Chris!

“Fun With EasyMock” by fellow StackOverflow user Burt Beckwith is a good blog post that provides more detail. Notable excerpt:

Basically the flow that I tend to use is:

  1. Create a mock
  2. call expect(mock.[method call]).andReturn([result]) for each expected call
  3. call mock.[method call], then EasyMock.expectLastCall() for each expected void call
  4. call replay(mock) to switch from “record” mode to “playback” mode
  5. inject the mock as needed
  6. call the test method
  7. call verify(mock) to assure that all expected calls happened



回答3:


If you only want access to the parameters for later, you might also appreciate the Captures class which is new to EasyMock 2.4.

You can use an instance of the "Capture" class in place of a matcher. When your mocked method is invoked, the Capture instance will store the parameter it was invoked with.

Capture<ChartPanel> captured = new Capture<ChartPanel>();
// setChartPanel is going to be called during execution;
// we want to verify some things about the ChartPanel
// instance it's invoked with
chartMock.setChartPanel(capture(captured));
replay(chartMock);

ufdm.setChartAnnotater(chartMock);
// afterPropertiesSet triggers the setChartPanel call...
ufdm.afterPropertiesSet();
verify(chartMock);

// verify some things about the ChartPanel parameter our
// mock object was invoked with
assertSame(plot, captured.getValue().getChart().getPlot());



回答4:


You might want to check out PowerMock. EasyMock is based on the proxy reflection API meaning everything is a proxy and you can only test interfaces, and thus only non-final methods and classes. This might work for some, but if you're testing the world as built, you'll need more power.

With PowerMock the Java 5 instrumentation API removes the limitations. No need to write mock object implementations of the object to be tested (just ugly IMO). Couple PowerMock with Mockito (or JMockit) and you'll really be off to the races.

Of course, there is the other direction of rewriting your code to be more easily tested, which is generally a good idea too, if possible.




回答5:


In situations like these I've found that making a nested class in my unit test class and overriding the methods with special requirements in that way is the best route. So if you're testing ClassA which has that method with the parameters you need to access, you'd do something like:

class MockClassA extends ClassA {
    @Override
    void specialMethod(String param1, String param2) {
        // do logging or manipulation of some sort
        super.specialMethod(param1,param2); // if you need to
    }
}

In my unit testing code, I then just use this instance instead. Just treat it as if it was any other mock object. Much easier than mixing libraries, which I agree is probably not a good idea.



来源:https://stackoverflow.com/questions/859031/easymock-void-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!