/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.modules.utils.testing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.util.Log; import androidx.annotation.Nullable; import com.android.modules.utils.testing.ExtendedMockitoRule.MockStatic; import com.android.modules.utils.testing.ExtendedMockitoRule.SpyStatic; import org.junit.Test; import org.junit.runner.Description; import org.junit.runner.RunWith; import org.junit.runners.model.Statement; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoFramework; import org.mockito.MockitoSession; import org.mockito.exceptions.misusing.UnnecessaryStubbingException; import org.mockito.invocation.InvocationFactory; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.listeners.MockitoListener; import org.mockito.plugins.MockitoPlugins; import org.mockito.quality.Strictness; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Objects; import java.util.Set; import java.util.function.Supplier; @RunWith(MockitoJUnitRunner.class) public final class ExtendedMockitoRuleTest { public static final String TAG = ExtendedMockitoRuleTest.class.getSimpleName(); // Not a real test (i.e., it doesn't exist on this class), but it's passed to Description private static final String TEST_METHOD_BEING_EXECUTED = "testAmI..OrNot"; private @Mock Statement mStatement; private @Mock Runnable mRunnable; private @Mock StaticMockFixture mStaticMockFixture1; private @Mock StaticMockFixture mStaticMockFixture2; private @Mock StaticMockFixture mStaticMockFixture3; private final Description mDescription = newTestMethod(); private final ClassUnderTest mClassUnderTest = new ClassUnderTest(); private final ExtendedMockitoRule.Builder mBuilder = new ExtendedMockitoRule.Builder(mClassUnderTest); // Builder that doesn't clear inline methods at the end - should be used in methods that // need to verify mocks private final ExtendedMockitoRule.Builder mUnsafeBuilder = new ExtendedMockitoRule.Builder(mClassUnderTest).dontClearInlineMocks(); private final Supplier mSupplier1 = () -> { return mStaticMockFixture1; }; private final Supplier mSupplier2 = () -> { return mStaticMockFixture2; }; private final Supplier mSupplier3 = () -> { return mStaticMockFixture3; }; @Test public void testBuilder_constructor_null() { assertThrows(NullPointerException.class, () -> new ExtendedMockitoRule.Builder(null)); } @Test public void testBuilder_setStrictness_null() { assertThrows(NullPointerException.class, () -> mBuilder.setStrictness(null)); } @Test public void testBuilder_mockStatic_null() { assertThrows(NullPointerException.class, () -> mBuilder.mockStatic(null)); } @Test public void testBuilder_spyStatic_null() { assertThrows(NullPointerException.class, () -> mBuilder.spyStatic(null)); } @Test public void testBuilder_addStaticMockFixtures_null() { assertThrows(NullPointerException.class, () -> mBuilder.addStaticMockFixtures((Supplier) null)); } @Test public void testBuilder_afterSessionFinished_null() { assertThrows(NullPointerException.class, () -> mBuilder.afterSessionFinished(null)); } @Test public void testBuilder_setMockitoFrameworkForTesting_null() { assertThrows(NullPointerException.class, () -> mBuilder.setMockitoFrameworkForTesting(null)); } @Test public void testBuilder_setMockitoSessionForTesting_null() { assertThrows(NullPointerException.class, () -> mBuilder.setMockitoSessionForTesting(null)); } @Test public void testMocksInitialized() throws Throwable { mBuilder.build().apply(mStatement, mDescription).evaluate(); assertWithMessage("@Mock object").that(mClassUnderTest.mMock).isNotNull(); } @Test public void testMocksNotInitialized() throws Throwable { new ExtendedMockitoRule.Builder().build().apply(mStatement, mDescription).evaluate(); assertWithMessage("@Mock object").that(mClassUnderTest.mMock).isNull(); } @Test public void testStrictness_lenientByDefault() throws Throwable { applyRuleOnTestThatDoesntUseExpectation(/* strictness= */ null); } @Test public void testStrictness_lenient() throws Throwable { applyRuleOnTestThatDoesntUseExpectation(Strictness.LENIENT); } @Test public void testStrictness_warn() throws Throwable { applyRuleOnTestThatDoesntUseExpectation(Strictness.WARN); } @Test public void testStrictness_strict() throws Throwable { assertThrows(UnnecessaryStubbingException.class, () -> applyRuleOnTestThatDoesntUseExpectation(Strictness.STRICT_STUBS)); } @Test public void testMocksStatic() throws Throwable { ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class).build(); rule.apply(new Statement() { @Override public void evaluate() throws Throwable { doReturn("mocko()").when(() -> StaticClass.marco()); assertWithMessage("StaticClass.marco()") .that(StaticClass.marco()).isEqualTo("mocko()"); assertWithMessage("StaticClass.water()") .that(StaticClass.water()).isNull(); // not mocked } }, mDescription).evaluate(); Set> mockedClasses = rule.getMockedStaticClasses(mDescription); assertWithMessage("rule.getMockedStaticClasses()").that(mockedClasses) .containsExactly(StaticClass.class); assertThrows(RuntimeException.class, () -> mockedClasses.add(ExtendedMockitoRuleTest.class)); } @Test public void testMockStatic_sameClass() throws Throwable { mBuilder.mockStatic(StaticClass.class); assertThrows(IllegalStateException.class, () -> mBuilder.mockStatic(StaticClass.class)); } @Test public void testMocksStatic_multipleClasses() throws Throwable { ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class) .mockStatic(AnotherStaticClass.class).build(); rule.apply(new Statement() { @Override public void evaluate() throws Throwable { doReturn("mocko()").when(() -> StaticClass.marco()); doReturn("MOCKO()").when(() -> AnotherStaticClass.marco()); assertWithMessage("StaticClass.marco()") .that(StaticClass.marco()).isEqualTo("mocko()"); assertWithMessage("StaticClass.water()") .that(StaticClass.water()).isNull(); // not mocked assertWithMessage("AnotherStaticClass.marco()") .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()"); assertWithMessage("AnotherStaticClass.water()") .that(AnotherStaticClass.water()).isNull(); // not mocked } }, mDescription).evaluate(); Set> mockedClasses = rule.getMockedStaticClasses(mDescription); assertWithMessage("rule.getMockedStaticClasses()").that(mockedClasses) .containsExactly(StaticClass.class, AnotherStaticClass.class); assertThrows(RuntimeException.class, () -> mockedClasses.add(ExtendedMockitoRuleTest.class)); } @Test public void testMockStatic_ruleAndAnnotation() throws Throwable { ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class).build(); rule.apply(new Statement() { @Override public void evaluate() throws Throwable { doReturn("mocko()").when(() -> StaticClass.marco()); doReturn("MOCKO()").when(() -> AnotherStaticClass.marco()); assertWithMessage("StaticClass.marco()") .that(StaticClass.marco()).isEqualTo("mocko()"); assertWithMessage("StaticClass.water()") .that(StaticClass.water()).isNull(); // not mocked assertWithMessage("AnotherStaticClass.marco()") .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()"); assertWithMessage("AnotherStaticClass.water()") .that(AnotherStaticClass.water()).isNull(); // not mocked } }, newTestMethod(new MockStaticAnnotation(AnotherStaticClass.class))).evaluate(); } // Ideally, we should test the annotations indirectly (i.e., by asserting their static classes // are properly mocked, but pragmatically speaking, testing the getSpiedStatic() is enough - and // much simpler @Test public void testMockStatic_fromEverywhere() throws Throwable { ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class).build(); Set> mockedClasses = rule.getMockedStaticClasses(newTestMethod(SubClass.class, new MockStaticAnnotation(AnotherStaticClass.class))); assertWithMessage("rule.getMockedStaticClasses()").that(mockedClasses).containsExactly( StaticClass.class, AnotherStaticClass.class, StaticClassMockedBySuperClass.class, AnotherStaticClassMockedBySuperClass.class, StaticClassMockedBySubClass.class, AnotherStaticClassMockedBySubClass.class); assertThrows(RuntimeException.class, () -> mockedClasses.add(ExtendedMockitoRuleTest.class)); } @Test public void testSpyStatic() throws Throwable { ExtendedMockitoRule rule = mBuilder.spyStatic(StaticClass.class).build(); rule.apply(new Statement() { @Override public void evaluate() throws Throwable { doReturn("mocko()").when(() -> StaticClass.marco()); assertWithMessage("StaticClass.marco()") .that(StaticClass.marco()).isEqualTo("mocko()"); assertWithMessage("StaticClass.water()") .that(StaticClass.water()).isEqualTo("polo"); } }, mDescription).evaluate(); Set> spiedClasses = rule.getSpiedStaticClasses(mDescription); assertWithMessage("rule.getSpiedStaticClasses()").that(spiedClasses) .containsExactly(StaticClass.class); assertThrows(RuntimeException.class, () -> spiedClasses.add(ExtendedMockitoRuleTest.class)); } @Test public void testSpyStatic_sameClass() throws Throwable { mBuilder.spyStatic(StaticClass.class); assertThrows(IllegalStateException.class, () -> mBuilder.spyStatic(StaticClass.class)); } @Test public void testSpyStatic_multipleClasses() throws Throwable { ExtendedMockitoRule rule = mBuilder.spyStatic(StaticClass.class) .spyStatic(AnotherStaticClass.class).build(); rule.apply(new Statement() { @Override public void evaluate() throws Throwable { doReturn("mocko()").when(() -> StaticClass.marco()); doReturn("MOCKO()").when(() -> AnotherStaticClass.marco()); assertWithMessage("StaticClass.marco()") .that(StaticClass.marco()).isEqualTo("mocko()"); assertWithMessage("StaticClass.water()") .that(StaticClass.water()).isEqualTo("polo"); assertWithMessage("AnotherStaticClass.marco()") .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()"); assertWithMessage("AnotherStaticClass.water()") .that(AnotherStaticClass.water()).isEqualTo("POLO"); } }, mDescription).evaluate(); Set> spiedClasses = rule.getSpiedStaticClasses(mDescription); assertWithMessage("rule.getSpiedStaticClasses()").that(spiedClasses) .containsExactly(StaticClass.class, AnotherStaticClass.class); assertThrows(RuntimeException.class, () -> spiedClasses.add(ExtendedMockitoRuleTest.class)); } @Test public void testSpyStatic_ruleAndAnnotation() throws Throwable { ExtendedMockitoRule rule = mBuilder.spyStatic(StaticClass.class).build(); rule.apply(new Statement() { @Override public void evaluate() throws Throwable { doReturn("mocko()").when(() -> StaticClass.marco()); doReturn("MOCKO()").when(() -> AnotherStaticClass.marco()); assertWithMessage("StaticClass.marco()") .that(StaticClass.marco()).isEqualTo("mocko()"); assertWithMessage("StaticClass.water()") .that(StaticClass.water()).isEqualTo("polo"); assertWithMessage("AnotherStaticClass.marco()") .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()"); assertWithMessage("AnotherStaticClass.water()") .that(AnotherStaticClass.water()).isEqualTo("POLO"); } }, newTestMethod(new SpyStaticAnnotation(AnotherStaticClass.class))).evaluate(); } // Ideally, we should test the annotations indirectly (i.e., by asserting their static classes // are properly spied, but pragmatically speaking, testing the getSpiedStatic() is enough - and // much simpler @Test public void testSpyStatic_fromEverywhere() throws Throwable { ExtendedMockitoRule rule = mBuilder.spyStatic(StaticClass.class).build(); Set> spiedClasses = rule.getSpiedStaticClasses(newTestMethod(SubClass.class, new SpyStaticAnnotation(AnotherStaticClass.class))); assertWithMessage("rule.getSpiedStaticClasses()").that(spiedClasses).containsExactly( StaticClass.class, AnotherStaticClass.class, StaticClassSpiedBySuperClass.class, AnotherStaticClassSpiedBySuperClass.class, StaticClassSpiedBySubClass.class, AnotherStaticClassSpiedBySubClass.class); assertThrows(RuntimeException.class, () -> spiedClasses.add(ExtendedMockitoRuleTest.class)); } @Test public void testMockAndSpyStatic() throws Throwable { ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class) .spyStatic(AnotherStaticClass.class).build(); rule.apply(new Statement() { @Override public void evaluate() throws Throwable { doReturn("mocko()").when(() -> StaticClass.marco()); doReturn("MOCKO()").when(() -> AnotherStaticClass.marco()); assertWithMessage("StaticClass.marco()") .that(StaticClass.marco()).isEqualTo("mocko()"); assertWithMessage("StaticClass.water()") .that(StaticClass.water()).isNull(); // not mocked assertWithMessage("AnotherStaticClass.marco()") .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()"); assertWithMessage("AnotherStaticClass.water()") .that(AnotherStaticClass.water()).isEqualTo("POLO"); } }, mDescription).evaluate(); Set> spiedStaticClasses = rule.getSpiedStaticClasses(mDescription); assertWithMessage("rule.getSpiedStaticClasses()").that(spiedStaticClasses) .containsExactly(AnotherStaticClass.class); assertThrows(RuntimeException.class, () -> spiedStaticClasses.add(ExtendedMockitoRuleTest.class)); Set> mockedStaticClasses = rule.getMockedStaticClasses(mDescription); assertWithMessage("rule.getMockedStaticClasses()").that(mockedStaticClasses) .containsExactly(StaticClass.class); assertThrows(RuntimeException.class, () -> mockedStaticClasses.add(ExtendedMockitoRuleTest.class)); } @Test public void testMockAndSpyStatic_sameClass() throws Throwable { mBuilder.mockStatic(StaticClass.class); assertThrows(IllegalStateException.class, () -> mBuilder.spyStatic(StaticClass.class)); } @Test public void testSpyAndMockStatic_sameClass() throws Throwable { mBuilder.spyStatic(StaticClass.class); assertThrows(IllegalStateException.class, () -> mBuilder.mockStatic(StaticClass.class)); } @Test public void testAddStaticMockFixtures_once() throws Throwable { InOrder inOrder = inOrder(mStaticMockFixture1, mStaticMockFixture2); mUnsafeBuilder .addStaticMockFixtures(mSupplier1, mSupplier2) .build().apply(mStatement, mDescription).evaluate(); inOrder.verify(mStaticMockFixture1).setUpMockedClasses(any()); inOrder.verify(mStaticMockFixture2).setUpMockedClasses(any()); inOrder.verify(mStaticMockFixture1).setUpMockBehaviors(); inOrder.verify(mStaticMockFixture2).setUpMockBehaviors(); inOrder.verify(mStaticMockFixture2).tearDown(); inOrder.verify(mStaticMockFixture1).tearDown(); } @Test public void testAddStaticMockFixtures_twice() throws Throwable { InOrder inOrder = inOrder(mStaticMockFixture1, mStaticMockFixture2, mStaticMockFixture3, mStaticMockFixture3); mUnsafeBuilder .addStaticMockFixtures(mSupplier1, mSupplier2) .addStaticMockFixtures(mSupplier3) .build().apply(mStatement, mDescription).evaluate(); inOrder.verify(mStaticMockFixture1).setUpMockedClasses(any()); inOrder.verify(mStaticMockFixture2).setUpMockedClasses(any()); inOrder.verify(mStaticMockFixture3).setUpMockedClasses(any()); inOrder.verify(mStaticMockFixture1).setUpMockBehaviors(); inOrder.verify(mStaticMockFixture2).setUpMockBehaviors(); inOrder.verify(mStaticMockFixture3).setUpMockBehaviors(); inOrder.verify(mStaticMockFixture3).tearDown(); inOrder.verify(mStaticMockFixture2).tearDown(); inOrder.verify(mStaticMockFixture1).tearDown(); } @Test public void testMockAndSpyStaticAndAddStaticMockFixtures() throws Throwable { InOrder inOrder = inOrder(mStaticMockFixture1, mStaticMockFixture2, mStaticMockFixture3, mStaticMockFixture3); mUnsafeBuilder .mockStatic(StaticClass.class) .spyStatic(AnotherStaticClass.class) .addStaticMockFixtures(mSupplier1, mSupplier2) .addStaticMockFixtures(mSupplier3) .build() .apply(new Statement() { @Override public void evaluate() throws Throwable { doReturn("mocko()").when(() -> StaticClass.marco()); doReturn("MOCKO()").when(() -> AnotherStaticClass.marco()); assertWithMessage("StaticClass.marco()") .that(StaticClass.marco()).isEqualTo("mocko()"); assertWithMessage("StaticClass.water()") .that(StaticClass.water()).isNull(); // not mocked assertWithMessage("AnotherStaticClass.marco()") .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()"); assertWithMessage("AnotherStaticClass.water()") .that(AnotherStaticClass.water()).isEqualTo("POLO"); } }, mDescription).evaluate(); inOrder.verify(mStaticMockFixture1).setUpMockedClasses(any()); inOrder.verify(mStaticMockFixture2).setUpMockedClasses(any()); inOrder.verify(mStaticMockFixture3).setUpMockedClasses(any()); inOrder.verify(mStaticMockFixture1).setUpMockBehaviors(); inOrder.verify(mStaticMockFixture2).setUpMockBehaviors(); inOrder.verify(mStaticMockFixture3).setUpMockBehaviors(); inOrder.verify(mStaticMockFixture3).tearDown(); inOrder.verify(mStaticMockFixture2).tearDown(); inOrder.verify(mStaticMockFixture1).tearDown(); } @Test public void testAfterSessionFinished() throws Throwable { mUnsafeBuilder.afterSessionFinished(mRunnable).build().apply(mStatement, mDescription) .evaluate(); verify(mRunnable).run(); } @Test public void testAfterSessionFinished_whenSessionFailsToFinish() throws Throwable { MockitoSessionThatFailsToFinish mockitoSession = new MockitoSessionThatFailsToFinish(); Exception thrown = assertThrows(Exception.class, () -> mUnsafeBuilder.afterSessionFinished(mRunnable) .setMockitoSessionForTesting(mockitoSession) .build().apply(mStatement, mDescription).evaluate()); assertWithMessage("exception").that(thrown).isSameInstanceAs(mockitoSession.e); verify(mRunnable).run(); } @Test public void testMockitoFrameworkCleared() throws Throwable { MyMockitoFramework mockitoFramework = new MyMockitoFramework(); mBuilder.setMockitoFrameworkForTesting(mockitoFramework).build() .apply(mStatement, mDescription) .evaluate(); assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue(); } @Test public void testMockitoFrameworkNotCleared_whenSetOnBuilder() throws Throwable { MyMockitoFramework mockitoFramework = new MyMockitoFramework(); mBuilder.dontClearInlineMocks().setMockitoFrameworkForTesting(mockitoFramework).build() .apply(mStatement, mDescription) .evaluate(); assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isFalse(); } @Test public void testMockitoFrameworkCleared_whenTestFails() throws Throwable { MyMockitoFramework mockitoFramework = new MyMockitoFramework(); Exception exception = new Exception("D'OH!"); Exception thrown = assertThrows(Exception.class, () -> mBuilder.setMockitoFrameworkForTesting(mockitoFramework).build() .apply(new Statement() { @Override public void evaluate() throws Throwable { throw exception; } }, mDescription).evaluate()); assertWithMessage("exception").that(thrown).isSameInstanceAs(exception); assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue(); } @Test public void testMockitoFrameworkCleared_whenAfterSessionFinished() throws Throwable { MyMockitoFramework mockitoFramework = new MyMockitoFramework(); RuntimeException exception = new RuntimeException("D'OH!"); Exception thrown = assertThrows(Exception.class, () -> mBuilder.setMockitoFrameworkForTesting(mockitoFramework) .afterSessionFinished(() -> { throw exception; }).build().apply(mStatement, mDescription).evaluate()); assertWithMessage("exception").that(thrown).isSameInstanceAs(exception); assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue(); } @Test public void testMockitoFrameworkCleared_whenStaticMockFixturesFailed() throws Throwable { MyMockitoFramework mockitoFramework = new MyMockitoFramework(); RuntimeException exception = new RuntimeException("D'OH!"); doThrow(exception).when(mStaticMockFixture1).tearDown(); Exception thrown = assertThrows(Exception.class, () -> mBuilder.setMockitoFrameworkForTesting(mockitoFramework) .addStaticMockFixtures(mSupplier1).build().apply(mStatement, mDescription) .evaluate()); assertWithMessage("exception").that(thrown).isSameInstanceAs(exception); assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue(); } @Test public void testMockitoFrameworkCleared_whenSessionFailsToFinish() throws Throwable { MyMockitoFramework mockitoFramework = new MyMockitoFramework(); MockitoSessionThatFailsToFinish mockitoSession = new MockitoSessionThatFailsToFinish(); Exception thrown = assertThrows(Exception.class, () -> mBuilder.setMockitoFrameworkForTesting(mockitoFramework) .setMockitoSessionForTesting(mockitoSession).build() .apply(mStatement, mDescription).evaluate()); assertWithMessage("exception").that(thrown).isSameInstanceAs(mockitoSession.e); assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue(); } @Test public void testGetClearInlineMethodsAtTheEnd() throws Throwable { assertWithMessage("getClearInlineMethodsAtTheEnd() by default") .that(mBuilder.build().getClearInlineMethodsAtTheEnd(mDescription)).isTrue(); assertWithMessage("getClearInlineMethodsAtTheEnd() when built with dontClearInlineMocks()") .that(mBuilder.dontClearInlineMocks().build() .getClearInlineMethodsAtTheEnd(mDescription)) .isFalse(); } private void applyRuleOnTestThatDoesntUseExpectation(@Nullable Strictness strictness) throws Throwable { Log.d(TAG, "applyRuleOnTestThatDoesntUseExpectation(): strictness= " + strictness); if (strictness != null) { mBuilder.setStrictness(strictness); } mBuilder.build().apply(new Statement() { @Override public void evaluate() throws Throwable { when(mClassUnderTest.mMock.getMeaningOfLife()).thenReturn(42); } }, mDescription).evaluate(); } private static Description newTestMethod(Annotation... annotations) { return newTestMethod(ClassUnderTest.class, annotations); } private static Description newTestMethod(Class testClass, Annotation... annotations) { return Description.createTestDescription(testClass, TEST_METHOD_BEING_EXECUTED, annotations); } private static final class ClassUnderTest { @Mock public DumbObject mMock; } private static final class StaticClass { public static String marco() { Log.d(TAG, "StaticClass.marco() called"); return "polo"; } public static String water() { Log.d(TAG, "StaticClass.water() called"); return "polo"; } } private static final class AnotherStaticClass { public static String marco() { Log.d(TAG, "AnotherStaticClass.marco() called"); return "POLO"; } public static String water() { Log.d(TAG, "AnotherStaticClass.water() called"); return "POLO"; } } private static class DumbObject { public int getMeaningOfLife() { Log.d(TAG, "getMeaningOfLife() called"); throw new UnsupportedOperationException("Ask Bard"); } } // Used on tests that check if the clearInlineMocks() is called - such tests cannot mock a // MockitoFramework because of that private static final class MyMockitoFramework implements MockitoFramework { private static int sCounter; private final int mId = ++sCounter; public boolean called; @Override public MockitoFramework removeListener(MockitoListener arg0) { return null; } @Override public MockitoPlugins getPlugins() { return null; } @Override public InvocationFactory getInvocationFactory() { return null; } @Override public void clearInlineMocks() { called = true; } @Override public void clearInlineMock(Object arg0) { } @Override public MockitoFramework addListener(MockitoListener arg0) { return null; } @Override public String toString() { return "MyMockitoFramework-" + mId; } }; // Used on tests that check if the clearInlineMocks() is called - such tests cannot mock a // MockitoSession because of that private static final class MockitoSessionThatFailsToFinish implements MockitoSession { public final RuntimeException e = new RuntimeException("D'OH!"); @Override public void setStrictness(Strictness strictness) { } @Override public void finishMocking() { throw e; } @Override public void finishMocking(Throwable failure) { throw e; } } private abstract static class ClassAnnotation implements Annotation { private Class mAnnotationType; private Class mClass; private ClassAnnotation(Class annotationType, Class clazz) { mAnnotationType = annotationType; mClass = clazz; } @Override public final Class annotationType() { return mAnnotationType; } public final Class value() { return mClass; } @Override public int hashCode() { return Objects.hash(mAnnotationType, mClass); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ClassAnnotation other = (ClassAnnotation) obj; return Objects.equals(mAnnotationType, other.mAnnotationType) && Objects.equals(mClass, other.mClass); } @Override public String toString() { return getClass().getSimpleName() + "[" + mClass.getSimpleName() + "]"; } } private static final class SpyStaticAnnotation extends ClassAnnotation implements SpyStatic { private SpyStaticAnnotation(Class clazz) { super(SpyStatic.class, clazz); } } private static final class MockStaticAnnotation extends ClassAnnotation implements MockStatic { private MockStaticAnnotation(Class clazz) { super(MockStatic.class, clazz); } } private static final class StaticClassMockedBySuperClass { } private static final class AnotherStaticClassMockedBySuperClass { } private static final class StaticClassSpiedBySuperClass { } private static final class AnotherStaticClassSpiedBySuperClass { } @SpyStatic(StaticClassSpiedBySuperClass.class) @SpyStatic(AnotherStaticClassSpiedBySuperClass.class) @MockStatic(StaticClassMockedBySuperClass.class) @MockStatic(AnotherStaticClassMockedBySuperClass.class) private static class SuperClass { } private static final class StaticClassMockedBySubClass { } private static final class AnotherStaticClassMockedBySubClass { } private static final class StaticClassSpiedBySubClass { } private static final class AnotherStaticClassSpiedBySubClass { } @SpyStatic(StaticClassSpiedBySubClass.class) @SpyStatic(AnotherStaticClassSpiedBySubClass.class) @MockStatic(StaticClassMockedBySubClass.class) @MockStatic(AnotherStaticClassMockedBySubClass.class) private static final class SubClass extends SuperClass{ } }