Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do Java mocking frameworks work?

This is NOT a question about which is the best framework, etc.

I have never used a mocking framework and I'm a bit puzzled by the idea. How does it know how to create the mock object? Is it done at runtime or does it generate a file? How do you know its behavior? And most importantly – what is the workflow of using such a framework (what is the step-by-step for creating a test)?

Can anyone explain? You can choose whichever framework you like for example, just say what it is.

like image 293
Amir Rachum Avatar asked Jun 07 '10 21:06

Amir Rachum


People also ask

What is a mocking framework Java?

Mockito is a mocking framework, JAVA-based library that is used for effective unit testing of JAVA applications. Mockito is used to mock interfaces so that a dummy functionality can be added to a mock interface that can be used in unit testing.

How do mocks work?

To isolate the behavior of the object you want to test you replace the other objects by mocks that simulate the behavior of the real objects. So in simple words, mocking is creating objects that simulate the behavior of real objects. In unit testing we want to test methods of one class in isolation.

How does Mockito mock work?

Simply put, Mockito works by storing and retrieving method invocation details on mocks using method interception. Method interception is a technique used in Aspect Oriented Programming(AOP) to address cross-cutting concerns in a software system like logging, statistics etc., by intercepting method calls.

What are Mocking frameworks?

What is a mocking framework? Mocking frameworks are used to generate replacement objects like Stubs and Mocks. Mocking frameworks complement unit testing frameworks by isolating dependencies but are not substitutes for unit testing frameworks.


2 Answers

A mocking framework takes the redundancy and boilerplate out of a mocking test.

It knows to create the Mock object because you tell it to, of course (unless you meant something else with that question).

The "standard" way of creating a mock object is to use/abuse the java.lang.reflect.Proxy class to create a runtime implementation of the interface. This is done at runtime. Proxy has a limitation in that it cannot proxy concrete classes. To accomplish mocking of concrete classes requires dynamic bytecode creation that creates subclasses that override the real implementation of the public methods with essentially what would be done with a Proxy (record the method parameters and return a pre-determined value). This has a limitation in that it cannot subclass final classes. For that, you have solutions like JDave, which (I believe, I didn't confirm this) muck with the classloader to remove the final designation on the class before loading it, so the class isn't in fact final at runtime as far as the JVM is concerned.

The Mocking framework is basically all about capturing the parameters and verifying them against pre-determined expectations, and then returning a pre-configured or reasonable default value. It doesn't behave in any particular way, which is the point. The calling code is being verified that it calls the method with the correct parameter, and perhaps how it reacts to a specific return values or thrown exceptions. Any side effects or real accomplishments of the call on the real object do not happen.

Here is a real example from a project, using JMock with JUnit4. I have added comments to explain what is going on.

 @RunWith(JMock.class) //The JMock Runner automatically checks that the expectations of the mock were actually run at the end of the test so that you don't have to do it with a line of code in every test. public class SecuredPresentationMapTest {  private Mockery context = new JUnit4Mockery(); //A Mockery holds the state about all of the Mocks. The JUnit4Mockery ensures that a failed mock throws the same Error as any other JUnit failure.  @Test public void testBasicMap() {     final IPermissionsLookup lookup = context.mock(IPermissionsLookup.class); //Creating a mock for the interface IPermissionsLookup.     context.checking(new Expectations(){{ //JMock uses some innovative but weird double brace initialization as its standard idom.         oneOf(lookup).canRead(SecuredEntity.ACCOUNTING_CONTRACT);             //expect exactly one call to the IPermissionsLookup.canRead method with the the enum of ACCOUNTING_CONTRACT as the value. Failure to call the method at all causes the test to fail.             will(returnValue(true)); //when the previous method is called correctly, return true;     }});      Map<String, Component> map = new SecuredPresentationMap(lookup, SecuredEntity.ACCOUNTING_CONTRACT);     //This creates the real object under test, but passes a mock lookup rather than the real implementation.     JLabel value = new JLabel();     map.put("", value);     assertThat(((JLabel) map.get("")), is(value)); //This ensures that the Map returns the value placed, which it should based on the fact that the mock returned true to the security check.   } } 

If the mock passed in was ignored, the test would have failed. If the map fails to return the value placed in it the test fails (that is standard JUnit).

What is being tested here and in another opposite test is that depending on what the IPermissionsLookup interface says about the security the Map changes its behavior about what is returned. This is the base good case. The other test, the mock returns false and something else is expected from the Map. Using the mock ensures that the map relies on the IPermissionsLookup method to determine the security posture and what is being returned.

like image 80
Yishai Avatar answered Sep 30 '22 01:09

Yishai


I will speak of the framework that I use ( jmock ), but others do something very similar.

How does it know how to create the mock object?

It does not, you tell the framework that you require a mock object and you give it a type ( ideally an interface ) of the object that you would like to mock. Behind the scenes the mock framework uses a combination of reflection and, sometimes, byte-code rewrites to create a mock object.

Is it done in runtime or generates a file?

jMock creates it at runtime.

How do you know its behavior?

Mock objects are pretty dumb. You specify the behavior that you expect of them.

And most importantly - what is the work flow of using such a framework (what is the step-by-step for creating a test).

One very important thing that framework must provide is an ability to check that expected behavior has been observed during the test execution.

jmock does it by introducing specific test runner that checks that all expectations on all declared mock objects after the test has finished. If something does not match, the exception is thrown.

Usually the pattern is:

  1. Acquire mock factory ( called Mockery in jmock )out of thin air ( with specific no-args constructor ).
  2. Create required mock objects.
  3. Setup expectation on mock objects
  4. Call the method you are testing, passing mocks instead of real objects
  5. If your method returns some values, check expected value with regular assertXXX methods.
like image 40
Alexander Pogrebnyak Avatar answered Sep 30 '22 01:09

Alexander Pogrebnyak