Skip to content

Instantly share code, notes, and snippets.

@ahasbini
Created December 11, 2019 20:27
Show Gist options
  • Save ahasbini/a2c4f88f0aff2b83c3b74f27c42354d0 to your computer and use it in GitHub Desktop.
Save ahasbini/a2c4f88f0aff2b83c3b74f27c42354d0 to your computer and use it in GitHub Desktop.
package test.ahasbini.com.test;
import android.util.Log;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.exceptions.misusing.PotentialStubbingProblem;
import org.mockito.internal.creation.settings.CreationSettings;
import org.mockito.internal.exceptions.Reporter;
import org.mockito.internal.junit.MockitoTestListener;
import org.mockito.internal.junit.TestFinishedEvent;
import org.mockito.internal.listeners.StubbingLookupListener;
import org.mockito.invocation.Invocation;
import org.mockito.invocation.MatchableInvocation;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.mock.MockCreationSettings;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Stubbing;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import static org.mockito.Mockito.mockingDetails;
/**
* Created by ahasbini on 25-Mar-18.
*/
public class MockitoOverloadInstrumentationTest extends BaseTest {
private static final String TAG = MockitoOverloadInstrumentationTest.class.getSimpleName();
@Mock
private MyInterface myInterface;
@Rule
public RuleChain ruleChain = RuleChain
.outerRule(unusedStubsHandlerRule = new UnusedStubsHandlerRule())
.around(new TestRule() {
@Override
public Statement apply(Statement base, Description description) {
try {
return mockitoRule.apply(base, new FrameworkMethod(
MockitoOverloadInstrumentationTest.this
.getClass().getMethod(description.getMethodName())),
MockitoOverloadInstrumentationTest.this);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
});
public UnusedStubsHandlerRule unusedStubsHandlerRule;
public MockitoRule mockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
@Before
public void setupStrictMockito() {
Mockito.framework().addListener(mockitoTestListener);
MockitoAnnotations.initMocks(this);
}
@Test
public void testOverload() {
// Set Up
Mockito.when(myInterface
.myMethod(Mockito.anyString(), Mockito.anyString()))
.thenReturn("Mocked Hello World!");
Example example = new Example(myInterface);
// Test
example.start();
Mockito.verify(myInterface, Mockito.timeout(10000L))
.myMethod(Mockito.anyString(), Mockito.anyString());
}
@Test
public void testUnusedStubbing() {
// Set Up
unusedStubsHandlerRule.setVerifyExceptionThrown(true);
Mockito.when(myInterface.myMethod()).thenReturn(true);
Mockito.when(myInterface
.myMethod(Mockito.anyString(), Mockito.anyString()))
.thenReturn("Mocked Hello World!");
Example example = new Example(myInterface);
// Test
example.start();
}
@Test
public void testAllStubbingsUsedCorrectly() {
// Set Up
Mockito.when(myInterface.myMethod()).thenReturn(false);
Mockito.when(myInterface
.myMethod(Mockito.anyString(), Mockito.anyString()))
.thenReturn("Mocked Hello World!");
Example example = new Example(myInterface);
// Test
example.start();
}
@Test(expected = PotentialStubbingProblem.class)
public void testPotentialArgsMismatch() {
// Set Up
unusedStubsHandlerRule.setVerifyExceptionThrown(true);
Mockito.when(myInterface
.myMethod("foo", "bar"))
.thenReturn("Mocked Foo Bar!");
Example example = new Example(myInterface);
// Test
example.start();
}
// @Test
// public void dummyTest() {
// unusedStubsHandlerRule.setVerifyExceptionThrown(true);
// }
@After
public void tearDownStrictMockito() {
Mockito.framework().removeListener(mockitoTestListener);
}
private final MockitoTestListener mockitoTestListener = new MockitoTestListener() {
@Override
public void testFinished(TestFinishedEvent event) {
}
@Override
public void onMockCreated(Object mock, MockCreationSettings settings) {
Log.i(TAG, "onMockCreated: called");
CreationSettings creationSettings = (CreationSettings) settings;
@SuppressWarnings("unchecked") ArrayList<StubbingLookupListener> stubbingLookupListeners =
(ArrayList<StubbingLookupListener>) creationSettings.getStubbingLookupListeners();
Assert.assertTrue("mock settings has more than one StubbingLookupListener",
stubbingLookupListeners.size() == 1);
stubbingLookupListeners.clear();
stubbingLookupListeners.add(strictStubbingLookupListenerImpl);
Log.i(TAG, "onMockCreated: getStubbingLookupListeners: " +
stubbingLookupListeners);
}
};
private final StubbingLookupListener strictStubbingLookupListenerImpl =
new StubbingLookupListener() {
@Override
public void onStubbingLookup(Invocation invocation, MatchableInvocation stubbingFound) {
if (stubbingFound == null) {
//If stubbing was not found for invocation it means that either the mock invocation was not stubbed or
//we have a stubbing arg mismatch.
List<Invocation> argMismatchStubbings = potentialArgMismatches(invocation);
if (!argMismatchStubbings.isEmpty()) {
Reporter.potentialStubbingProblem(invocation, argMismatchStubbings);
}
} else {
//when strict stubs are in use, every time a stub is realized in the code it is implicitly marked as verified
//this way, the users don't have to repeat themselves to verify stubbed invocations (DRY)
invocation.markVerified();
}
}
private List<Invocation> potentialArgMismatches(Invocation invocation) {
List<Invocation> matchingStubbings = new LinkedList<Invocation>();
Collection<Stubbing> stubbings = mockingDetails(invocation.getMock()).getStubbings();
for (Stubbing s : stubbings) {
if (!s.wasUsed() && s.getInvocation().getMethod().equals(invocation.getMethod())) {
matchingStubbings.add(s.getInvocation());
}
}
return matchingStubbings;
}
};
}
@ahasbini
Copy link
Author

Some other classes this file depends on:

MyInterface.java:

package test.ahasbini.com.test;

/**
 * Created by ahasbini on 25-Mar-18.
 */

public interface MyInterface {

    boolean myMethod();

    String myMethod(String i, String j);
}

UnusedStubsHandlerRule.java:

package test.ahasbini.com.test;

import android.util.Log;

import junit.framework.AssertionFailedError;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mockito.exceptions.misusing.UnnecessaryStubbingException;

/**
 * Created by ahasbini on 17-Apr-18.
 */

public class UnusedStubsHandlerRule implements TestRule {

    private static final String TAG = UnusedStubsHandlerRule.class.getSimpleName();

    private boolean verifyExceptionThrown = false;

    public void setVerifyExceptionThrown(boolean verifyExceptionThrown) {
        this.verifyExceptionThrown = verifyExceptionThrown;
    }

    @Override
    public Statement apply(final Statement base, Description description) {
        return new Statement() {

            @Override
            public void evaluate() throws Throwable {
                try {
                    base.evaluate();
                } catch (UnnecessaryStubbingException e) {
                    if (!verifyExceptionThrown) {
                        throw e;
                    } else {
                        Log.i(TAG, "evaluate: thrown exception has been verified");
                        verifyExceptionThrown = false;
                    }
                }
                if (verifyExceptionThrown) {
                    throw new AssertionFailedError("exception was not thrown, but was ignored");
                }
            }
        };
    }
}

Example.java:

package test.ahasbini.com.test;

import android.util.Log;

/**
 * Created by ahasbini on 25-Mar-18.
 */

public class Example {

    private static final String TAG = Example.class.getSimpleName();

    private final MyInterface myInterface;

    public Example(MyInterface myInterface) {
        this.myInterface = myInterface;
    }

    public void start() {
        if (!myInterface.myMethod()) {
            Log.i(TAG, "start: " + myInterface.myMethod("hello", "world").toString());
        }
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment