package org.mockitousage.constructor; import org.junit.Test; import org.mockito.exceptions.base.MockitoException; import org.mockito.mock.SerializableMode; import org.mockitousage.IMethods; import org.mockitoutil.TestBase; import java.util.List; import static junit.framework.TestCase.*; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; public class CreatingMocksWithConstructorTest extends TestBase { static abstract class AbstractMessage { private final String message; AbstractMessage() { this.message = "hey!"; } String getMessage() { return message; } } static class Message extends AbstractMessage {} class InnerClass extends AbstractMessage {} @Test public void can_create_mock_with_constructor() { Message mock = mock(Message.class, withSettings().useConstructor().defaultAnswer(CALLS_REAL_METHODS)); //the message is a part of state of the mocked type that gets initialized in constructor assertEquals("hey!", mock.getMessage()); } @Test public void can_mock_abstract_classes() { AbstractMessage mock = mock(AbstractMessage.class, withSettings().useConstructor().defaultAnswer(CALLS_REAL_METHODS)); assertEquals("hey!", mock.getMessage()); } @Test public void can_spy_abstract_classes() { AbstractMessage mock = spy(AbstractMessage.class); assertEquals("hey!", mock.getMessage()); } @Test public void can_mock_inner_classes() { InnerClass mock = mock(InnerClass.class, withSettings().useConstructor().outerInstance(this).defaultAnswer(CALLS_REAL_METHODS)); assertEquals("hey!", mock.getMessage()); } static class HasConstructor { HasConstructor(String x) {} } @Test public void exception_message_when_constructor_not_found() { try { //when spy(HasConstructor.class); //then fail(); } catch (MockitoException e) { assertThat(e).hasMessage("Unable to create mock instance of type 'HasConstructor'"); assertThat(e.getCause()).hasMessageContaining("0-arg constructor"); } } @Test public void mocking_inner_classes_with_wrong_outer_instance() { try { //when mock(InnerClass.class, withSettings().useConstructor().outerInstance("foo").defaultAnswer(CALLS_REAL_METHODS)); //then fail(); } catch (MockitoException e) { assertThat(e).hasMessage("Unable to create mock instance of type 'InnerClass'"); assertThat(e.getCause()).hasMessageContaining("Please ensure that the outer instance has correct type and that the target class has 0-arg constructor."); } } @Test public void mocking_interfaces_with_constructor() { //at the moment this is allowed however we can be more strict if needed //there is not much sense in creating a spy of an interface mock(IMethods.class, withSettings().useConstructor()); spy(IMethods.class); } @Test public void prevents_across_jvm_serialization_with_constructor() { try { //when mock(AbstractMessage.class, withSettings().useConstructor().serializable(SerializableMode.ACROSS_CLASSLOADERS)); //then fail(); } catch (MockitoException e) { assertEquals("Mocks instantiated with constructor cannot be combined with " + SerializableMode.ACROSS_CLASSLOADERS + " serialization mode.", e.getMessage()); } } static abstract class AbstractThing { abstract String name(); String fullName() { return "abstract " + name(); } } @Test public void abstract_method_returns_default() { AbstractThing thing = spy(AbstractThing.class); assertEquals("abstract null", thing.fullName()); } @Test public void abstract_method_stubbed() { AbstractThing thing = spy(AbstractThing.class); when(thing.name()).thenReturn("me"); assertEquals("abstract me", thing.fullName()); } @Test public void calls_real_interface_method() { List list = mock(List.class, withSettings().defaultAnswer(CALLS_REAL_METHODS)); assertNull(list.get(1)); } }