/* * Copyright (c) 2007 Mockito contributors * This program is made available under the terms of the MIT License. */ package org.mockitousage.stubbing; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.*; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.net.Socket; import java.util.List; import java.util.Locale; import javax.net.SocketFactory; import org.junit.Test; import org.mockito.InOrder; import org.mockito.MockSettings; import org.mockito.exceptions.verification.TooManyActualInvocations; import org.mockitoutil.TestBase; public class DeepStubbingTest extends TestBase { static class Person { Address address; public Address getAddress() { return address; } public Address getAddress(String addressName) { return address; } public FinalClass getFinalClass() { return null; } } static class Address { Street street; public Street getStreet() { return street; } public Street getStreet(Locale locale) { return street; } } static class Street { String name; public String getName() { return name; } public String getLongName() { return name; } } static final class FinalClass {} interface First { Second getSecond(); String getString(); } interface Second extends List {} class BaseClassGenerics {} class ReversedGenerics extends BaseClassGenerics { ReversedGenerics reverse() { return null; } A finalMethod() { return null; } } class SuperOfReversedGenerics extends ReversedGenerics {} @Test public void myTest() throws Exception { SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); when(sf.createSocket(anyString(), eq(80))).thenReturn(null); sf.createSocket("what", 80); } @Test public void simpleCase() throws Exception { OutputStream out = new ByteArrayOutputStream(); Socket socket = mock(Socket.class); when(socket.getOutputStream()).thenReturn(out); assertSame(out, socket.getOutputStream()); } /** * Test that deep stubbing works for one intermediate level */ @Test public void oneLevelDeep() throws Exception { OutputStream out = new ByteArrayOutputStream(); SocketFactory socketFactory = mock(SocketFactory.class, RETURNS_DEEP_STUBS); when(socketFactory.createSocket().getOutputStream()).thenReturn(out); assertSame(out, socketFactory.createSocket().getOutputStream()); } /** * Test that stubbing of two mocks stubs don't interfere */ @Test public void interactions() throws Exception { OutputStream out1 = new ByteArrayOutputStream(); OutputStream out2 = new ByteArrayOutputStream(); SocketFactory sf1 = mock(SocketFactory.class, RETURNS_DEEP_STUBS); when(sf1.createSocket().getOutputStream()).thenReturn(out1); SocketFactory sf2 = mock(SocketFactory.class, RETURNS_DEEP_STUBS); when(sf2.createSocket().getOutputStream()).thenReturn(out2); assertSame(out1, sf1.createSocket().getOutputStream()); assertSame(out2, sf2.createSocket().getOutputStream()); } /** * Test that stubbing of methods of different arguments don't interfere */ @Test public void withArguments() throws Exception { OutputStream out1 = new ByteArrayOutputStream(); OutputStream out2 = new ByteArrayOutputStream(); OutputStream out3 = new ByteArrayOutputStream(); SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); when(sf.createSocket().getOutputStream()).thenReturn(out1); when(sf.createSocket("google.com", 80).getOutputStream()).thenReturn(out2); when(sf.createSocket("stackoverflow.com", 80).getOutputStream()).thenReturn(out3); assertSame(out1, sf.createSocket().getOutputStream()); assertSame(out2, sf.createSocket("google.com", 80).getOutputStream()); assertSame(out3, sf.createSocket("stackoverflow.com", 80).getOutputStream()); } /** * Test that deep stubbing work with argument patterns */ @Test public void withAnyPatternArguments() throws Exception { OutputStream out = new ByteArrayOutputStream(); // TODO: should not use javax in case it changes SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); when(sf.createSocket(anyString(), anyInt()).getOutputStream()).thenReturn(out); assertSame(out, sf.createSocket("google.com", 80).getOutputStream()); assertSame(out, sf.createSocket("stackoverflow.com", 8080).getOutputStream()); } /** * Test that deep stubbing work with argument patterns */ @Test public void withComplexPatternArguments() throws Exception { OutputStream out1 = new ByteArrayOutputStream(); OutputStream out2 = new ByteArrayOutputStream(); SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); when(sf.createSocket(anyString(), eq(80)).getOutputStream()).thenReturn(out1); when(sf.createSocket(anyString(), eq(8080)).getOutputStream()).thenReturn(out2); assertSame(out2, sf.createSocket("stackoverflow.com", 8080).getOutputStream()); assertSame(out1, sf.createSocket("google.com", 80).getOutputStream()); assertSame(out2, sf.createSocket("google.com", 8080).getOutputStream()); assertSame(out1, sf.createSocket("stackoverflow.com", 80).getOutputStream()); } /** * Test that deep stubbing work with primitive expected values */ @Test public void withSimplePrimitive() throws Exception { int a = 32; SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); when(sf.createSocket().getPort()).thenReturn(a); assertEquals(a, sf.createSocket().getPort()); } /** * Test that deep stubbing work with primitive expected values with * pattern method arguments */ @Test public void withPatternPrimitive() throws Exception { int a = 12, b = 23, c = 34; SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); when(sf.createSocket(eq("stackoverflow.com"), eq(80)).getPort()).thenReturn(a); when(sf.createSocket(eq("google.com"), anyInt()).getPort()).thenReturn(b); when(sf.createSocket(eq("stackoverflow.com"), eq(8080)).getPort()).thenReturn(c); assertEquals(b, sf.createSocket("google.com", 80).getPort()); assertEquals(c, sf.createSocket("stackoverflow.com", 8080).getPort()); assertEquals(a, sf.createSocket("stackoverflow.com", 80).getPort()); } @Test public void unnamed_to_string() { SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); assertNotNull(sf.toString()); } @Test public void named_to_string() { MockSettings settings = withSettings().name("name of mock").defaultAnswer(RETURNS_DEEP_STUBS); SocketFactory sf = mock(SocketFactory.class, settings); assertEquals("name of mock", sf.toString()); } Person person = mock(Person.class, RETURNS_DEEP_STUBS); @Test public void shouldStubbingBasicallyWorkFine() { // given given(person.getAddress().getStreet().getName()).willReturn("Norymberska"); // when String street = person.getAddress().getStreet().getName(); // then assertEquals("Norymberska", street); } @Test public void shouldVerificationBasicallyWorkFine() { // given person.getAddress().getStreet().getName(); // then verify(person.getAddress().getStreet()).getName(); } @Test public void verification_work_with_argument_Matchers_in_nested_calls() { // given person.getAddress("111 Mock Lane").getStreet(); person.getAddress("111 Mock Lane").getStreet(Locale.ITALIAN).getName(); // then verify(person.getAddress(anyString())).getStreet(); verify(person.getAddress(anyString()).getStreet(Locale.CHINESE), never()).getName(); verify(person.getAddress(anyString()).getStreet(eq(Locale.ITALIAN))).getName(); } @Test public void deep_stub_return_same_mock_instance_if_invocation_matchers_matches() { when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep"); person.getAddress("the docks").getStreet().getName(); assertSame( person.getAddress("the docks").getStreet(), person.getAddress(anyString()).getStreet()); assertSame( person.getAddress(anyString()).getStreet(), person.getAddress(anyString()).getStreet()); assertSame( person.getAddress("the docks").getStreet(), person.getAddress("the docks").getStreet()); assertSame( person.getAddress(anyString()).getStreet(), person.getAddress("the docks").getStreet()); assertSame( person.getAddress("111 Mock Lane").getStreet(), person.getAddress("the docks").getStreet()); } @Test public void times_never_atLeast_atMost_verificationModes_should_work() { when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep"); person.getAddress("the docks").getStreet().getName(); person.getAddress("the docks").getStreet().getName(); person.getAddress("the docks").getStreet().getName(); person.getAddress("the docks").getStreet(Locale.ITALIAN).getName(); verify(person.getAddress("the docks").getStreet(), times(3)).getName(); verify(person.getAddress("the docks").getStreet(Locale.CHINESE), never()).getName(); verify(person.getAddress("the docks").getStreet(Locale.ITALIAN), atMostOnce()).getName(); } @Test public void inOrder_only_work_on_the_very_last_mock_but_it_works() { when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep"); when(person.getAddress(anyString()).getStreet(Locale.ITALIAN).getName()).thenReturn("deep"); when(person.getAddress(anyString()).getStreet(Locale.CHINESE).getName()).thenReturn("deep"); person.getAddress("the docks").getStreet().getName(); person.getAddress("the docks").getStreet().getLongName(); person.getAddress("the docks").getStreet(Locale.ITALIAN).getName(); person.getAddress("the docks").getStreet(Locale.CHINESE).getName(); InOrder inOrder = inOrder( person.getAddress("the docks").getStreet(), person.getAddress("the docks").getStreet(Locale.CHINESE), person.getAddress("the docks").getStreet(Locale.ITALIAN)); inOrder.verify(person.getAddress("the docks").getStreet(), times(1)).getName(); inOrder.verify(person.getAddress("the docks").getStreet()).getLongName(); inOrder.verify(person.getAddress("the docks").getStreet(Locale.ITALIAN), atLeast(1)) .getName(); inOrder.verify(person.getAddress("the docks").getStreet(Locale.CHINESE)).getName(); } @Test public void verificationMode_only_work_on_the_last_returned_mock() { // 1st invocation on Address mock (stubbing) when(person.getAddress("the docks").getStreet().getName()).thenReturn("deep"); // 2nd invocation on Address mock (real) person.getAddress("the docks").getStreet().getName(); // 3rd invocation on Address mock (verification) // (Address mock is not in verification mode) verify(person.getAddress("the docks").getStreet()).getName(); try { verify(person.getAddress("the docks"), times(1)).getStreet(); fail(); } catch (TooManyActualInvocations e) { assertThat(e.getMessage()).contains("Wanted 1 time").contains("But was 3 times"); } } @Test public void shouldFailGracefullyWhenClassIsFinal() { // when FinalClass value = new FinalClass(); given(person.getFinalClass()).willReturn(value); // then assertEquals(value, person.getFinalClass()); } @Test public void deep_stub_does_not_try_to_mock_generic_final_classes() { First first = mock(First.class, RETURNS_DEEP_STUBS); assertNull(first.getString()); assertNull(first.getSecond().get(0)); } @Test public void deep_stub_does_not_stack_overflow_on_reversed_generics() { SuperOfReversedGenerics mock = mock(SuperOfReversedGenerics.class, RETURNS_DEEP_STUBS); when((Object) mock.reverse().finalMethod()).thenReturn(5L); assertThat(mock.reverse().finalMethod()).isEqualTo(5L); } }