/* * Copyright (c) 2006 Rogério Liesenfeld * This file is subject to the terms of the MIT license (see LICENSE.txt). */ package mockit; import java.applet.*; import java.awt.*; import java.lang.reflect.*; import java.net.*; import java.rmi.*; import java.sql.*; import java.util.concurrent.atomic.*; import javax.swing.*; import javax.swing.plaf.basic.*; import org.junit.*; import org.junit.rules.*; import static org.junit.Assert.*; public final class MockUpTest { @Rule public final ExpectedException thrown = ExpectedException.none(); @Test public void attemptToApplyMockUpWithoutTheTargetType() { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("No target type"); new MockUp() {}; } // Mock-ups for classes //////////////////////////////////////////////////////////////////////////////////////////// @Test public void mockUpClass() { new MockUp<Applet>() { @Mock int getComponentCount() { return 123; } }; assertEquals(123, new Applet().getComponentCount()); } static final class Main { static final AtomicIntegerFieldUpdater<Main> atomicCount = AtomicIntegerFieldUpdater.newUpdater(Main.class, "count"); volatile int count; int max = 2; boolean increment() { while (true) { int currentCount = count; if (currentCount >= max) { return false; } if (atomicCount.compareAndSet(this, currentCount, currentCount + 1)) { return true; } } } } @Test public void mockUpGivenClass() { final Main main = new Main(); AtomicIntegerFieldUpdater<?> atomicCount = Deencapsulation.getField(Main.class, AtomicIntegerFieldUpdater.class); new MockUp<AtomicIntegerFieldUpdater<?>>(atomicCount.getClass()) { boolean second; @Mock public boolean compareAndSet(Object obj, int expect, int update) { assertSame(main, obj); assertEquals(0, expect); assertEquals(1, update); if (second) { return true; } second = true; return false; } }; assertTrue(main.increment()); } @Test public void attemptToMockGivenClassButPassNull() { thrown.expect(NullPointerException.class); new MockUp<Applet>((Class<?>) null) {}; } @Test public void attemptToMockGivenInstanceButPassNull() { thrown.expect(NullPointerException.class); new MockUp<Applet>((Applet) null) {}; } @SuppressWarnings("rawtypes") static class MockForGivenClass extends MockUp { @SuppressWarnings("unchecked") MockForGivenClass() { super(Applet.class); } @Mock String getParameter(String s) { return "mock"; } } @Test public void mockUpGivenClassUsingNamedMockUp() { new MockForGivenClass(); String s = new Applet().getParameter("test"); assertEquals("mock", s); } // Mock-ups for interfaces ///////////////////////////////////////////////////////////////////////////////////////// @Test public void mockUpInterface() throws Exception { ResultSet mock = new MockUp<ResultSet>() { @Mock boolean next() { return true; } }.getMockInstance(); assertTrue(mock.next()); } @Test public void mockUpGivenInterface() { Runnable r = new MockUp<Runnable>(Runnable.class) { @Mock public void run() {} }.getMockInstance(); r.run(); } @Test public <M extends Runnable & ResultSet> void mockUpTwoInterfacesAtOnce() throws Exception { M mock = new MockUp<M>() { @Mock void run() {} @Mock boolean next() { return true; } }.getMockInstance(); mock.run(); assertTrue(mock.next()); } @SuppressWarnings("TypeParameterExtendsFinalClass") @Test public <M extends Applet & Runnable> void attemptToMockUpClassAndInterfaceAtOnce() throws Exception { thrown.expect(IllegalArgumentException.class); thrown.expectMessage("java.applet.Applet is not an interface"); new MockUp<M>() { @Mock String getParameter(String s) { return s.toLowerCase(); } @Mock void run() {} }; } public interface SomeInterface { int doSomething(); } @Test public void callEqualsMethodOnMockedUpInterface() { SomeInterface proxy1 = new MockUp<SomeInterface>(){}.getMockInstance(); SomeInterface proxy2 = new MockUp<SomeInterface>(){}.getMockInstance(); //noinspection SimplifiableJUnitAssertion,EqualsWithItself assertTrue(proxy1.equals(proxy1)); assertFalse(proxy1.equals(proxy2)); assertFalse(proxy2.equals(proxy1)); //noinspection ObjectEqualsNull assertFalse(proxy1.equals(null)); } @Test public void callHashCodeMethodOnMockedUpInterface() { SomeInterface proxy = new MockUp<SomeInterface>(){}.getMockInstance(); assertEquals(System.identityHashCode(proxy), proxy.hashCode()); } @Test public void callToStringMethodOnMockedUpInterface() { SomeInterface proxy = new MockUp<SomeInterface>(){}.getMockInstance(); assertEquals(proxy.getClass().getName() + '@' + Integer.toHexString(proxy.hashCode()), proxy.toString()); } // Mock-ups for other situations /////////////////////////////////////////////////////////////////////////////////// @Test public void mockUpUsingInvocationParameters() { new MockUp<Applet>() { @Mock void $init(Invocation inv) { Applet it = inv.getInvokedInstance(); assertNotNull(it); } @Mock int getBaseline(Invocation inv, int w, int h) { return inv.proceed(); } }; int i = new Applet().getBaseline(20, 15); assertEquals(-1, i); } public static class PublicNamedMockUpWithNoInvocationParameters extends MockUp<Applet> { boolean executed; @Mock public void $init() { executed = true; } @Mock public String getParameter(String s) { return "45"; } } @Test public void publicNamedMockUpWithNoInvocationParameter() { PublicNamedMockUpWithNoInvocationParameters mockup = new PublicNamedMockUpWithNoInvocationParameters(); Applet applet = new Applet(); assertTrue(mockup.executed); String parameter = applet.getParameter("test"); assertEquals("45", parameter); } @SuppressWarnings("deprecation") @Test public void mockingOfAnnotatedClass() throws Exception { new MockUp<RMISecurityException>() { @Mock void $init(String s) { assertNotNull(s); } }; assertTrue(RMISecurityException.class.isAnnotationPresent(Deprecated.class)); Constructor<RMISecurityException> aConstructor = RMISecurityException.class.getDeclaredConstructor(String.class); assertTrue(aConstructor.isAnnotationPresent(Deprecated.class)); Deprecated deprecated = aConstructor.getAnnotation(Deprecated.class); assertNotNull(deprecated); } @Test public void mockSameClassTwiceUsingSeparateMockups() { Applet a = new Applet(); class MockUp1 extends MockUp<Applet> { @Mock void play(URL url) {} } new MockUp1(); a.play(null); new MockUp<Applet>() { @Mock void showStatus(String s) {} }; a.play(null); // still mocked a.showStatus(""); } interface B { int aMethod(); Integer anotherMethod(); } @Test public void mockNonPublicInterface() { B b = new MockUp<B>() { @Mock int aMethod() { return 1; } }.getMockInstance(); assertEquals(1, b.aMethod()); assertEquals(0, b.anotherMethod().intValue()); } public interface C { int method1(); int method2(); } @Test public void mockSameInterfaceTwiceUsingSeparateMockups() { class MockUp1 extends MockUp<C> { @Mock int method1() { return 1; } } C c1 = new MockUp1().getMockInstance(); assertEquals(1, c1.method1()); assertEquals(0, c1.method2()); C c2 = new MockUp<C>() { @Mock int method2() { return 2; } }.getMockInstance(); assertEquals(0, c2.method1()); // not mocked because c2 belongs to a second implementation class for C assertEquals(2, c2.method2()); // Instances c1 and c2 belong to different mocked classes, so c1 is unaffected: assertEquals(1, c1.method1()); assertEquals(0, c1.method2()); } @Test public void mockConstructorOfInnerClass() { final BasicColorChooserUI outer = new BasicColorChooserUI(); final boolean[] constructed = {false}; new MockUp<BasicColorChooserUI.PropertyHandler>() { @Mock void $init(BasicColorChooserUI o) { assertSame(outer, o); constructed[0] = true; } }; outer.new PropertyHandler(); assertTrue(constructed[0]); } @Test public void callMockMethodFromAWTEventDispatchingThread() throws Exception { new MockUp<Panel>() { @Mock int getComponentCount() { return 10; } }; SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { int i = new Panel().getComponentCount(); assertEquals(10, i); } }); } }