JMock matchers with setAttribute(String, Object)

2019-07-25 09:25发布

问题:

I am facing issue while expecting a setAttribute call from a mock.

MyClass {
  public final void setAttribute(String name, Object value) {
  // Do Something
}

myClass.setAttribute("Key", "Value");

While invoking the setAttribute operation, String is passed as a value. I have a mock of the above class by the name mockMyClass and in my Expectations block I have the below code.

oneOf(mockMyClass).setAttribute(with(equal("Key")), with(equal("Value")));

I have also tried using any, just to see if the generic works, but that is also giving the same issue.

Exception I am getting:

java.lang.IllegalArgumentException: not all parameters were given explicit matchers: either all parameters must be specified by matchers or all must be specified by values, you cannot mix matchers and values

Initially I was trying without any matchers and was getting the exception:

oneOf(mockMyClass).setAttribute("Key", "Value");

org.jmock.api.ExpectationError: unexpected invocation

How to get this working? I intend to check for actual values.

回答1:

make method not final

 public void setAttribute(String name, Object value) {}

and use

oneOf(mockMyClass).setAttribute("Key", "Value");

or with matcher any();

from jmock -- ClassImposteriser cannot create mocks of final classes or mock final methods.

Mocking Classes with jMock and the ClassImposteriser Because it uses Java's standard reflection capability, the default configuration of the jMock framework can only mock interfaces, not classes. (Actually, we consider that to be a good thing because it encourages the design to focus on communication between objects rather than static classification or data storage). However, the ClassImposteriser extension class uses the CGLIB 2.1 and Objenesis libraries to create mock objects of classes as well as interfaces. This is useful when working with legacy code to tease apart dependencies between tightly coupled classes.

The ClassImposteriser creates mock instances without calling the constructor of the mocked class. So classes with constructors that have arguments or call overideable methods of the object can be safely mocked. However, the ClassImposteriser cannot create mocks of final classes or mock final methods.

If you want to mock final classes or final methods, the JDave library includes an unfinalizer Instrumentation agent that can unfinalise classes before they are loaded by the JVM. They can then be mocked by the ClassImposteriser.