/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockitousage.basicapi;
import org.fest.assertions.Assertions;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.mockito.exceptions.base.MockitoException;
import org.mockito.internal.matchers.Any;
import org.mockito.internal.stubbing.answers.ThrowsException;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockitousage.IMethods;
import org.mockitoutil.SimpleSerializationUtil;
import org.mockitoutil.TestBase;
import java.io.ByteArrayOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Observable;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;
import static org.mockitoutil.SimpleSerializationUtil.*;
@SuppressWarnings({"unchecked", "serial"})
public class MocksSerializationTest extends TestBase implements Serializable {
private static final long serialVersionUID = 6160482220413048624L;
@Test
public void should_allow_throws_exception_to_be_serializable() throws Exception {
// given
Bar mock = mock(Bar.class, new ThrowsException(new RuntimeException()));
// when-serialize then-deserialize
serializeAndBack(mock);
}
@Test
public void should_allow_method_delegation() throws Exception {
// given
Bar barMock = mock(Bar.class, withSettings().serializable());
Foo fooMock = mock(Foo.class);
when(barMock.doSomething()).thenAnswer(new ThrowsException(new RuntimeException()));
//when-serialize then-deserialize
serializeAndBack(barMock);
}
@Test
public void should_allow_mock_to_be_serializable() throws Exception {
// given
IMethods mock = mock(IMethods.class, withSettings().serializable());
// when-serialize then-deserialize
serializeAndBack(mock);
}
@Test
public void should_allow_mock_and_boolean_value_to_serializable() throws Exception {
// given
IMethods mock = mock(IMethods.class, withSettings().serializable());
when(mock.booleanReturningMethod()).thenReturn(true);
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
assertTrue(readObject.booleanReturningMethod());
}
@Test
public void should_allow_mock_and_string_value_to_be_serializable() throws Exception {
// given
IMethods mock = mock(IMethods.class, withSettings().serializable());
String value = "value";
when(mock.stringReturningMethod()).thenReturn(value);
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
assertEquals(value, readObject.stringReturningMethod());
}
@Test
public void should_all_mock_and_serializable_value_to_be_serialized() throws Exception {
// given
IMethods mock = mock(IMethods.class, withSettings().serializable());
List<?> value = Collections.emptyList();
when(mock.objectReturningMethodNoArgs()).thenReturn(value);
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
assertEquals(value, readObject.objectReturningMethodNoArgs());
}
@Test
public void should_serialize_method_call_with_parameters_that_are_serializable() throws Exception {
IMethods mock = mock(IMethods.class, withSettings().serializable());
List<?> value = Collections.emptyList();
when(mock.objectArgMethod(value)).thenReturn(value);
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
assertEquals(value, readObject.objectArgMethod(value));
}
@Test
public void should_serialize_method_calls_using_any_string_matcher() throws Exception {
IMethods mock = mock(IMethods.class, withSettings().serializable());
List<?> value = Collections.emptyList();
when(mock.objectArgMethod(anyString())).thenReturn(value);
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
assertEquals(value, readObject.objectArgMethod(""));
}
@Test
public void should_verify_called_n_times_for_serialized_mock() throws Exception {
IMethods mock = mock(IMethods.class, withSettings().serializable());
List<?> value = Collections.emptyList();
when(mock.objectArgMethod(anyString())).thenReturn(value);
mock.objectArgMethod("");
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
verify(readObject, times(1)).objectArgMethod("");
}
@Test
public void should_verify_even_if_some_methods_called_after_serialization() throws Exception {
//given
IMethods mock = mock(IMethods.class, withSettings().serializable());
// when
mock.simpleMethod(1);
ByteArrayOutputStream serialized = serializeMock(mock);
IMethods readObject = deserializeMock(serialized, IMethods.class);
readObject.simpleMethod(1);
// then
verify(readObject, times(2)).simpleMethod(1);
//this test is working because it seems that java serialization mechanism replaces all instances
//of serialized object in the object graph (if there are any)
}
class Bar implements Serializable {
Foo foo;
public Foo doSomething() {
return foo;
}
}
class Foo implements Serializable {
Bar bar;
Foo() {
bar = new Bar();
bar.foo = this;
}
}
@Test
public void should_serialization_work() throws Exception {
//given
Foo foo = new Foo();
//when
foo = serializeAndBack(foo);
//then
assertSame(foo, foo.bar.foo);
}
@Test
public void should_stub_even_if_some_methods_called_after_serialization() throws Exception {
//given
IMethods mock = mock(IMethods.class, withSettings().serializable());
// when
when(mock.simpleMethod(1)).thenReturn("foo");
ByteArrayOutputStream serialized = serializeMock(mock);
IMethods readObject = deserializeMock(serialized, IMethods.class);
when(readObject.simpleMethod(2)).thenReturn("bar");
// then
assertEquals("foo", readObject.simpleMethod(1));
assertEquals("bar", readObject.simpleMethod(2));
}
@Test
public void should_verify_call_order_for_serialized_mock() throws Exception {
IMethods mock = mock(IMethods.class, withSettings().serializable());
IMethods mock2 = mock(IMethods.class, withSettings().serializable());
mock.arrayReturningMethod();
mock2.arrayReturningMethod();
// when
ByteArrayOutputStream serialized = serializeMock(mock);
ByteArrayOutputStream serialized2 = serializeMock(mock2);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
IMethods readObject2 = deserializeMock(serialized2, IMethods.class);
InOrder inOrder = inOrder(readObject, readObject2);
inOrder.verify(readObject).arrayReturningMethod();
inOrder.verify(readObject2).arrayReturningMethod();
}
@Test
public void should_remember_interactions_for_serialized_mock() throws Exception {
IMethods mock = mock(IMethods.class, withSettings().serializable());
List<?> value = Collections.emptyList();
when(mock.objectArgMethod(anyString())).thenReturn(value);
mock.objectArgMethod("happened");
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
verify(readObject, never()).objectArgMethod("never happened");
}
@Test
public void should_serialize_with_stubbing_callback() throws Exception {
// given
IMethods mock = mock(IMethods.class, withSettings().serializable());
CustomAnswersMustImplementSerializableForSerializationToWork answer =
new CustomAnswersMustImplementSerializableForSerializationToWork();
answer.string = "return value";
when(mock.objectArgMethod(anyString())).thenAnswer(answer);
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
assertEquals(answer.string, readObject.objectArgMethod(""));
}
class CustomAnswersMustImplementSerializableForSerializationToWork
implements Answer<Object>, Serializable {
private String string;
public Object answer(InvocationOnMock invocation) throws Throwable {
invocation.getArguments();
invocation.getMock();
return string;
}
}
@Test
public void should_serialize_with_real_object_spy() throws Exception {
// given
List<Object> list = new ArrayList<Object>();
List<Object> spy = mock(ArrayList.class, withSettings()
.spiedInstance(list)
.defaultAnswer(CALLS_REAL_METHODS)
.serializable());
when(spy.size()).thenReturn(100);
// when
ByteArrayOutputStream serialized = serializeMock(spy);
// then
List<?> readObject = deserializeMock(serialized, List.class);
assertEquals(100, readObject.size());
}
@Test
public void should_serialize_object_mock() throws Exception {
// given
Any mock = mock(Any.class);
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
deserializeMock(serialized, Any.class);
}
@Test
public void should_serialize_real_partial_mock() throws Exception {
// given
Any mock = mock(Any.class, withSettings().serializable());
when(mock.matches(anyObject())).thenCallRealMethod();
// when
ByteArrayOutputStream serialized = serializeMock(mock);
// then
Any readObject = deserializeMock(serialized, Any.class);
readObject.matches("");
}
class AlreadySerializable implements Serializable {}
@Test
public void should_serialize_already_serializable_class() throws Exception {
// given
AlreadySerializable mock = mock(AlreadySerializable.class, withSettings().serializable());
when(mock.toString()).thenReturn("foo");
// when
mock = serializeAndBack(mock);
// then
assertEquals("foo", mock.toString());
}
@Test
public void should_be_serialize_and_have_extra_interfaces() throws Exception {
//when
IMethods mock = mock(IMethods.class, withSettings().serializable().extraInterfaces(List.class));
IMethods mockTwo = mock(IMethods.class, withSettings().extraInterfaces(List.class).serializable());
//then
Assertions.assertThat((Object) serializeAndBack((List) mock))
.isInstanceOf(List.class)
.isInstanceOf(IMethods.class);
Assertions.assertThat((Object) serializeAndBack((List) mockTwo))
.isInstanceOf(List.class)
.isInstanceOf(IMethods.class);
}
static class NotSerializableAndNoDefaultConstructor {
NotSerializableAndNoDefaultConstructor(Observable o) { super(); }
}
@Test
public void should_fail_when_serializable_used_with_type_that_dont_implements_Serializable_and_dont_declare_a_no_arg_constructor() throws Exception {
try {
serializeAndBack(mock(NotSerializableAndNoDefaultConstructor.class, withSettings().serializable()));
fail("should have thrown an exception to say the object is not serializable");
} catch (MockitoException e) {
Assertions.assertThat(e.getMessage())
.contains(NotSerializableAndNoDefaultConstructor.class.getSimpleName())
.contains("serializable()")
.contains("implement Serializable")
.contains("no-arg constructor");
}
}
static class SerializableAndNoDefaultConstructor implements Serializable {
SerializableAndNoDefaultConstructor(Observable o) { super(); }
}
@Test
public void should_be_able_to_serialize_type_that_implements_Serializable_but_but_dont_declare_a_no_arg_constructor() throws Exception {
serializeAndBack(mock(SerializableAndNoDefaultConstructor.class));
}
public static class AClassWithPrivateNoArgConstructor {
private AClassWithPrivateNoArgConstructor() {}
List returningSomething() { return Collections.emptyList(); }
}
@Test
public void private_constructor_currently_not_supported_at_the_moment_at_deserialization_time() throws Exception {
// given
AClassWithPrivateNoArgConstructor mockWithPrivateConstructor = Mockito.mock(
AClassWithPrivateNoArgConstructor.class,
Mockito.withSettings().serializable()
);
try {
// when
SimpleSerializationUtil.serializeAndBack(mockWithPrivateConstructor);
fail("should have thrown an ObjectStreamException or a subclass of it");
} catch (ObjectStreamException e) {
// then
Assertions.assertThat(e.toString()).contains("no valid constructor");
}
}
@Test
@Ignore("Bug to fix !!! see issue 399")
public void BUG_ISSUE_399_try_some_mocks_with_current_answers() throws Exception {
IMethods iMethods = mock(IMethods.class, withSettings().serializable().defaultAnswer(RETURNS_DEEP_STUBS));
when(iMethods.iMethodsReturningMethod().linkedListReturningMethod().contains(anyString())).thenReturn(false);
serializeAndBack(iMethods);
}
}