/*
* 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.Test;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
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.TestBase;
import java.io.ByteArrayOutputStream;
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.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
import static org.mockitoutil.SimpleSerializationUtil.deserializeMock;
import static org.mockitoutil.SimpleSerializationUtil.serializeAndBack;
import static org.mockitoutil.SimpleSerializationUtil.serializeMock;
@SuppressWarnings({"unchecked", "serial"})
public class MocksSerializationForAnnotationTest extends TestBase implements Serializable {
private static final long serialVersionUID = 6160482220413048624L;
@Mock Any any;
@Mock(serializable=true) Bar barMock;
@Mock(serializable=true) IMethods imethodsMock;
@Mock(serializable=true) IMethods imethodsMock2;
@Mock(serializable=true) Any anyMock;
@Mock(serializable=true) AlreadySerializable alreadySerializableMock;
@Mock(extraInterfaces={List.class},serializable=true) IMethods imethodsWithExtraInterfacesMock;
@Test
public void should_allow_throws_exception_to_be_serializable() throws Exception {
// given
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 {
// when-serialize then-deserialize
serializeAndBack(imethodsMock);
}
@Test
public void should_allow_mock_and_boolean_value_to_serializable() throws Exception {
// given
when(imethodsMock.booleanReturningMethod()).thenReturn(true);
// when
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
// 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
String value = "value";
when(imethodsMock.stringReturningMethod()).thenReturn(value);
// when
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
// 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
List<?> value = Collections.emptyList();
when(imethodsMock.objectReturningMethodNoArgs()).thenReturn(value);
// when
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
// 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 {
List<?> value = Collections.emptyList();
when(imethodsMock.objectArgMethod(value)).thenReturn(value);
// when
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
// 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 {
List<?> value = Collections.emptyList();
when(imethodsMock.objectArgMethod(anyString())).thenReturn(value);
// when
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
assertEquals(value, readObject.objectArgMethod(""));
}
@Test
public void should_verify_called_n_times_for_serialized_mock() throws Exception {
List<?> value = Collections.emptyList();
when(imethodsMock.objectArgMethod(anyString())).thenReturn(value);
imethodsMock.objectArgMethod("");
// when
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
// 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 {
// when
imethodsMock.simpleMethod(1);
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
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
// when
when(imethodsMock.simpleMethod(1)).thenReturn("foo");
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
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 {
imethodsMock.arrayReturningMethod();
imethodsMock2.arrayReturningMethod();
// when
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
ByteArrayOutputStream serialized2 = serializeMock(imethodsMock2);
// 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 {
List<?> value = Collections.emptyList();
when(imethodsMock.objectArgMethod(anyString())).thenReturn(value);
imethodsMock.objectArgMethod("happened");
// when
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
verify(readObject, never()).objectArgMethod("never happened");
}
@Test
public void should_serialize_with_stubbing_callback() throws Exception {
// given
CustomAnswersMustImplementSerializableForSerializationToWork answer =
new CustomAnswersMustImplementSerializableForSerializationToWork();
answer.string = "return value";
when(imethodsMock.objectArgMethod(anyString())).thenAnswer(answer);
// when
ByteArrayOutputStream serialized = serializeMock(imethodsMock);
// then
IMethods readObject = deserializeMock(serialized, IMethods.class);
assertEquals(answer.string, readObject.objectArgMethod(""));
}
static 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 {
// when
ByteArrayOutputStream serialized = serializeMock(any);
// then
deserializeMock(serialized, Any.class);
}
@Test
public void should_serialize_real_partial_mock() throws Exception {
// given
when(anyMock.matches(anyObject())).thenCallRealMethod();
// when
ByteArrayOutputStream serialized = serializeMock(anyMock);
// then
Any readObject = deserializeMock(serialized, Any.class);
readObject.matches("");
}
class AlreadySerializable implements Serializable {}
@Test
public void should_serialize_already_serializable_class() throws Exception {
// given
when(alreadySerializableMock.toString()).thenReturn("foo");
// when
alreadySerializableMock = serializeAndBack(alreadySerializableMock);
// then
assertEquals("foo", alreadySerializableMock.toString());
}
@Test
public void should_be_serialize_and_have_extra_interfaces() throws Exception {
//then
Assertions.assertThat((Object) serializeAndBack((List) imethodsWithExtraInterfacesMock))
.isInstanceOf(List.class)
.isInstanceOf(IMethods.class);
}
static class NotSerializableAndNoDefaultConstructor {
NotSerializableAndNoDefaultConstructor(Observable o) { super(); }
}
public static class FailTestClass {
@Mock(serializable=true)
NotSerializableAndNoDefaultConstructor notSerializableAndNoDefaultConstructor;
}
@Test
public void should_fail_when_serializable_used_with_type_that_dont_implements_Serializable_and_dont_declare_a_no_arg_constructor() throws Exception {
try {
FailTestClass testClass = new FailTestClass();
MockitoAnnotations.initMocks(testClass);
serializeAndBack(testClass.notSerializableAndNoDefaultConstructor);
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(); }
}
public static class TestClassThatHoldValidField {
@Mock(serializable=true)
SerializableAndNoDefaultConstructor serializableAndNoDefaultConstructor;
}
@Test
public void should_be_able_to_serialize_type_that_implements_Serializable_but_but_dont_declare_a_no_arg_constructor() throws Exception {
TestClassThatHoldValidField testClass = new TestClassThatHoldValidField();
MockitoAnnotations.initMocks(testClass);
serializeAndBack(testClass.serializableAndNoDefaultConstructor);
}
}