/* * Copyright (c) 2006-2011 Rogério Liesenfeld * This file is subject to the terms of the MIT license (see LICENSE.txt). */ package mockit; import java.io.*; import java.util.*; import javax.security.auth.*; import javax.security.auth.callback.*; import javax.security.auth.login.*; import javax.security.auth.spi.*; import static mockit.Deencapsulation.*; import static mockit.Mockit.*; import static org.junit.Assert.*; import org.junit.*; import mockit.internal.state.*; @SuppressWarnings({"JUnitTestMethodWithNoAssertions", "ClassWithTooManyMethods"}) public final class MockAnnotationsTest { // The "code under test" for the tests in this class /////////////////////////////////////////////////////////////// private final CodeUnderTest codeUnderTest = new CodeUnderTest(); private boolean mockExecuted; static class CodeUnderTest { private final Collaborator dependency = new Collaborator(); void doSomething() { dependency.provideSomeService(); } int performComputation(int a, boolean b) { int i = dependency.getValue(); List<?> results = dependency.complexOperation(a, i); if (b) { dependency.setValue(i + results.size()); } return i; } } @SuppressWarnings({"UnusedDeclaration"}) static class Collaborator { static Object xyz; private int value; Collaborator() {} Collaborator(int value) { this.value = value; } private static String doInternal() { return "123"; } void provideSomeService() { throw new RuntimeException("Real provideSomeService() called"); } int getValue() { return value; } void setValue(int value) { this.value = value; } List<?> complexOperation(Object input1, Object... otherInputs) { return input1 == null ? Collections.emptyList() : Arrays.asList(otherInputs); } final void simpleOperation(int a, String b, Date c) {} } // Mocks without expectations ////////////////////////////////////////////////////////////////////////////////////// @Test public void mockWithNoExpectationsPassingMockClass() { Mockit.setUpMocks(MockCollaborator1.class); codeUnderTest.doSomething(); } @MockClass(realClass = Collaborator.class) static class MockCollaborator1 { @Mock void provideSomeService() {} } @Test public void mockWithNoExpectationsPassingMockInstance() { Mockit.setUpMocks(new MockCollaborator1()); codeUnderTest.doSomething(); } @Test public void setUpMockForSingleClassPassingAnnotatedMockInstance() { Mockit.setUpMock(new MockCollaborator1()); codeUnderTest.doSomething(); } @MockClass(realClass = Collaborator.class) public static class MockCollaborator6 { @Mock int getValue() { return 1; } } @Test public void setUpMockForSingleRealClassByPassingTheMockClassLiteral() { setUpMock(MockCollaborator6.class); assertEquals(1, new Collaborator().getValue()); } @Test public void setUpMockForSingleRealClassByPassingAMockClassInstance() { setUpMock(new MockCollaborator6()); assertEquals(1, new Collaborator().getValue()); } @Test public void setUpStubs() { Mockit.setUpMocksAndStubs(Collaborator.class); codeUnderTest.doSomething(); } static class MockCollaborator2 { @Mock void provideSomeService() {} } @Test public void setUpMockForGivenRealClass() { Mockit.setUpMock(Collaborator.class, MockCollaborator2.class); codeUnderTest.doSomething(); } @Test public void setUpMockForRealClassByName() { Mockit.setUpMock(Collaborator.class.getName(), MockCollaborator2.class); codeUnderTest.doSomething(); } @Test public void setUpMockForGivenRealClassPassingMockInstance() { Mockit.setUpMock(Collaborator.class, new MockCollaborator2()); codeUnderTest.doSomething(); } @Test public void setUpMockForRealClassByNamePassingMockInstance() { Mockit.setUpMock(Collaborator.class.getName(), new MockCollaborator2()); codeUnderTest.doSomething(); } @Test public void setUpMockForInterface() { BusinessInterface mock = Mockit.setUpMock(new MockCollaborator3()); mock.provideSomeService(); } interface BusinessInterface { void provideSomeService(); } @MockClass(realClass = BusinessInterface.class) static class MockCollaborator3 { @Mock void provideSomeService() {} } @Test(expected = RuntimeException.class) public void setUpAndTearDownMocks() { Mockit.setUpMocks(MockCollaborator1.class); codeUnderTest.doSomething(); Mockit.tearDownMocks(); codeUnderTest.doSomething(); } @Test public void setUpMocksFromInnerMockClassWithMockConstructor() { Mockit.setUpMocks(new MockCollaborator4()); assertFalse(mockExecuted); new CodeUnderTest().doSomething(); assertTrue(mockExecuted); } @MockClass(realClass = Collaborator.class) class MockCollaborator4 { @Mock void $init() { mockExecuted = true; } @Mock void provideSomeService() {} } @Test public void setUpMocksFromMockClassWithStaticMockMethod() { Mockit.setUpMocks(MockCollaborator5.class); codeUnderTest.doSomething(); } @MockClass(realClass = Collaborator.class) static class MockCollaborator5 { @Mock @Deprecated // to check that another annotation doesn't interfere, and to increase coverage static void provideSomeService() {} } // Mocks WITH expectations ///////////////////////////////////////////////////////////////////////////////////////// @Test public void setUpMocksContainingExpectations() { Mockit.setUpMocks(MockCollaboratorWithExpectations.class); int result = codeUnderTest.performComputation(2, true); assertEquals(0, result); } @MockClass(realClass = Collaborator.class) static class MockCollaboratorWithExpectations { @Mock(minInvocations = 1) int getValue() { return 0; } @Mock(maxInvocations = 2) void setValue(int value) { assertEquals(1, value); } @Mock List<?> complexOperation(Object input1, Object... otherInputs) { int i = (Integer) otherInputs[0]; assertEquals(0, i); List<Integer> values = new ArrayList<Integer>(); values.add((Integer) input1); return values; } @Mock(invocations = 0) void provideSomeService() {} } @Test(expected = AssertionError.class) public void setUpMockWithMinInvocationsExpectationButFailIt() { Mockit.setUpMocks(MockCollaboratorWithMinInvocationsExpectation.class); } @MockClass(realClass = Collaborator.class) static class MockCollaboratorWithMinInvocationsExpectation { @Mock(minInvocations = 2) int getValue() { return 1; } } @Test(expected = AssertionError.class) public void setUpMockWithMaxInvocationsExpectationButFailIt() { Mockit.setUpMocks(MockCollaboratorWithMaxInvocationsExpectation.class); new Collaborator().setValue(23); } @MockClass(realClass = Collaborator.class) static class MockCollaboratorWithMaxInvocationsExpectation { @Mock(maxInvocations = 0) void setValue(int v) { assertEquals(23, v); } } @Test(expected = AssertionError.class) public void setUpMockWithInvocationsExpectationButFailIt() { Mockit.setUpMocks(MockCollaboratorWithInvocationsExpectation.class); codeUnderTest.doSomething(); codeUnderTest.doSomething(); } @MockClass(realClass = Collaborator.class) static class MockCollaboratorWithInvocationsExpectation { @Mock(invocations = 1) void provideSomeService() {} } // Reentrant mocks ///////////////////////////////////////////////////////////////////////////////////////////////// @Test(expected = RuntimeException.class) public void setUpReentrantMock() { Mockit.setUpMocks(MockCollaboratorWithReentrantMock.class); codeUnderTest.doSomething(); } @MockClass(realClass = Collaborator.class) static class MockCollaboratorWithReentrantMock { Collaborator it; @Mock(reentrant = false) int getValue() { return 123; } @Mock(reentrant = true, invocations = 1) void provideSomeService() { it.provideSomeService(); } } // Mocks for constructors and static methods /////////////////////////////////////////////////////////////////////// @Test public void setUpMockForConstructor() { Mockit.setUpMocks(MockCollaboratorWithConstructorMock.class); new Collaborator(5); } @MockClass(realClass = Collaborator.class) static class MockCollaboratorWithConstructorMock { @Mock(invocations = 1) void $init(int value) { assertEquals(5, value); } } @Test public void setUpMockForStaticMethod() { Mockit.setUpMocks(MockCollaboratorForStaticMethod.class); Collaborator.doInternal(); } @MockClass(realClass = Collaborator.class) static class MockCollaboratorForStaticMethod { @Mock(invocations = 1) static String doInternal() { return ""; } } @Test public void setUpMockForSubclassConstructor() { Mockit.setUpMocks(MockSubCollaborator.class); new SubCollaborator(); } static class SubCollaborator extends Collaborator { SubCollaborator() {} } @MockClass(realClass = SubCollaborator.class) static class MockSubCollaborator { @Mock(invocations = 1) void $init() {} @SuppressWarnings({"UnusedDeclaration"}) native void doNothing(); } @Test // Note: this test only works under JDK 1.6+; JDK 1.5 does not support redefining natives. public void mockNativeMethodInClassWithRegisterNatives() { Mockit.setUpMocks(MockSystem.class); assertEquals(0, System.nanoTime()); Mockit.tearDownMocks(); assertTrue(System.nanoTime() > 0); } @MockClass(realClass = System.class) static class MockSystem { @Mock public static long nanoTime() { return 0; } } @Test // Note: this test only works under JDK 1.6+; JDK 1.5 does not support redefining natives. public void mockNativeMethodInClassWithoutRegisterNatives() throws Exception { Mockit.setUpMocks(MockFloat.class); assertEquals(0.0, Float.intBitsToFloat(2243019), 0.0); Mockit.tearDownMocks(); assertTrue(Float.intBitsToFloat(2243019) > 0); } @MockClass(realClass = Float.class) static class MockFloat { @SuppressWarnings({"UnusedDeclaration"}) @Mock public static float intBitsToFloat(int bits) { return 0; } } @Test public void setUpStartupMock() { Mockit.setUpStartupMocks(MockCollaborator1.class, new MockCollaborator4()); assertEquals(0, TestRun.mockFixture().getRedefinedClassCount()); } @Test public void setUpMockForJREClass() { MockThread mockThread = new MockThread(); Mockit.setUpMocks(mockThread); Thread.currentThread().interrupt(); assertTrue(mockThread.interrupted); } @MockClass(realClass = Thread.class) public static class MockThread { boolean interrupted; @Mock(invocations = 1) public void interrupt() { interrupted = true; } } @Test public void mockJREMethodAndConstructorForGivenRealClass() throws Exception { Mockit.setUpMock(LoginContext.class, MockLoginContextWithoutAnnotation.class); new LoginContext("test", (CallbackHandler) null).login(); } @Test public void mockJREMethodAndConstructorForGivenRealClassWithGivenMockInstance() throws Exception { Mockit.setUpMock(LoginContext.class, new MockLoginContextWithoutAnnotation()); new LoginContext("test", (CallbackHandler) null).login(); } public static class MockLoginContextWithoutAnnotation { MockLoginContextWithoutAnnotation() {} @Mock public void $init(String name, CallbackHandler callbackHandler) { assertEquals("test", name); assertNull(callbackHandler); } @Mock public void login() {} } @Test public void mockJREMethodAndConstructorUsingAnnotatedMockClass() throws Exception { Mockit.setUpMocks(new MockLoginContext()); new LoginContext("test", (CallbackHandler) null).login(); } @MockClass(realClass = LoginContext.class) public static class MockLoginContext { @Mock(invocations = 1) public void $init(String name, CallbackHandler callbackHandler) { assertEquals("test", name); assertNull(callbackHandler); } @Mock public void login() {} @Mock(maxInvocations = 1) public Subject getSubject() { return null; } } @Test public void mockJREMethodAndConstructorWithAnonymousMockClass() throws Exception { Mockit.setUpMock(LoginContext.class, new Object() { @Mock(minInvocations = 1) void $init(String name) { assertEquals("test", name); } @Mock(invocations = 1) void login() {} @Mock(maxInvocations = 1) void logout() {} }); new LoginContext("test").login(); } @Test(expected = LoginException.class) public void mockJREMethodAndConstructorWithMockUpClass() throws Exception { new MockUp<LoginContext>() { @Mock void $init(String name) { assertEquals("test", name); } @Mock void login() throws LoginException { throw new LoginException(); } }; new LoginContext("test").login(); } @Test public void mockPrivateMethodInJREClassByName() throws Exception { Mockit.setUpMock(LoginContext.class.getName(), new MockLoginContextForPrivateMethod()); Deencapsulation.invoke(new LoginContext(""), "clearState"); } static final class MockLoginContextForPrivateMethod { @Mock @SuppressWarnings({"UnusedDeclaration"}) void $init(String name) {} @Mock(invocations = 1) static void clearState() {} } @Test public void mockJREClassWithStubs() throws Exception { Mockit.setUpMocks(new MockLoginContextWithStubs()); LoginContext context = new LoginContext(""); context.login(); context.logout(); } @MockClass(realClass = LoginContext.class, stubs = {"(String)", "logout"}) final class MockLoginContextWithStubs { @Mock(invocations = 1) void login() {} } @Test public void mockJREClassWithInverseStubs() throws Exception { Mockit.setUpMocks(MockLoginContextWithInverseStubs.class); LoginContext context = new LoginContext("", null, null); context.login(); context.logout(); } @MockClass(realClass = LoginContext.class, stubs = "", inverse = true) static class MockLoginContextWithInverseStubs { @Mock(invocations = 1) static void login() {} } static class ClassWithStaticInitializers { static String str = "initialized"; // if final it would be a compile-time constant static final Object obj = new Object(); // constant, but only at runtime static { System.exit(1); } static void doSomething() {} static { try { Class.forName("NonExistentClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } @Test public void mockStaticInitializer() { new MockUp<ClassWithStaticInitializers>() { @Mock(invocations = 1) void $clinit() {} }; ClassWithStaticInitializers.doSomething(); assertNull(ClassWithStaticInitializers.str); assertNull(ClassWithStaticInitializers.obj); } static class AnotherClassWithStaticInitializers { static { System.exit(1); } static void doSomething() { throw new RuntimeException(); } } @Test public void stubOutStaticInitializer() throws Exception { Mockit.setUpMock(new MockForClassWithInitializer()); AnotherClassWithStaticInitializers.doSomething(); } @MockClass(realClass = AnotherClassWithStaticInitializers.class, stubs = "<clinit>") static class MockForClassWithInitializer { @Mock(minInvocations = 1, maxInvocations = 1) void doSomething() {} } @Test public void mockJREInterface() throws Exception { CallbackHandler callbackHandler = Mockit.setUpMock(new MockCallbackHandler()); callbackHandler.handle(new Callback[] {new NameCallback("Enter name:")}); } @MockClass(realClass = CallbackHandler.class) public static class MockCallbackHandler { @Mock(invocations = 1) public void handle(Callback[] callbacks) { assertEquals(1, callbacks.length); assertTrue(callbacks[0] instanceof NameCallback); } } @Test public void mockJREInterfaceWithMockUp() throws Exception { CallbackHandler callbackHandler = new MockUp<CallbackHandler>() { @Mock(invocations = 1) void handle(Callback[] callbacks) { assertEquals(1, callbacks.length); assertTrue(callbacks[0] instanceof NameCallback); } }.getMockInstance(); callbackHandler.handle(new Callback[] {new NameCallback("Enter name:")}); } @Test public void accessMockedInstanceThroughItField() throws Exception { final Subject testSubject = new Subject(); new MockUp<LoginContext>() { LoginContext it; @Mock(invocations = 1) void $init(String name, Subject subject) { assertNotNull(name); assertSame(testSubject, subject); assertNotNull(it); setField(it, subject); // forces setting of private field, since no setter is available } @Mock(invocations = 1) void login() { assertNotNull(it); assertNull(it.getSubject()); // returns null until the subject is authenticated setField(it, "loginSucceeded", true); // private field set to true when login succeeds } @Mock(invocations = 1) void logout() { assertNotNull(it); assertSame(testSubject, it.getSubject()); } }; LoginContext theMockedInstance = new LoginContext("test", testSubject); theMockedInstance.login(); theMockedInstance.logout(); } @Test public void reenterMockedMethodsThroughItField() throws Exception { // Create objects to be exercised by the code under test: Configuration configuration = new Configuration() { @Override public AppConfigurationEntry[] getAppConfigurationEntry(String name) { Map<String, ?> options = Collections.emptyMap(); return new AppConfigurationEntry[] { new AppConfigurationEntry( TestLoginModule.class.getName(), AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT, options) }; } }; LoginContext loginContext = new LoginContext("test", null, null, configuration); // Set up mocks: ReentrantMockLoginContext mockInstance = new ReentrantMockLoginContext(); // Exercise the code under test: assertNull(loginContext.getSubject()); loginContext.login(); assertNotNull(loginContext.getSubject()); assertTrue(mockInstance.loggedIn); mockInstance.ignoreLogout = true; loginContext.logout(); assertTrue(mockInstance.loggedIn); mockInstance.ignoreLogout = false; loginContext.logout(); assertFalse(mockInstance.loggedIn); } static final class ReentrantMockLoginContext extends MockUp<LoginContext> { LoginContext it; boolean ignoreLogout; boolean loggedIn; @Mock(reentrant = true) void login() throws LoginException { try { it.login(); loggedIn = true; } finally { it.getSubject(); } } @Mock(reentrant = true) void logout() throws LoginException { if (!ignoreLogout) { it.logout(); loggedIn = false; } } } public static class TestLoginModule implements LoginModule { public void initialize( Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { } public boolean login() { return true; } public boolean commit() { return true; } public boolean abort() { return false; } public boolean logout() { return true; } } @Test public void mockFileConstructor() { new MockUp<File>() { File it; @Mock void $init(String pathName) { Deencapsulation.setField(it, "path", "fixedPrefix/" + pathName); } }; File f = new File("test"); assertEquals("fixedPrefix/test", f.getPath()); } }