/* * Copyright (c) 2007 Mockito contributors * This program is made available under the terms of the MIT License. */ package org.mockitousage.stubbing; import org.assertj.core.api.Assertions; import org.junit.Test; import org.mockito.InOrder; import org.mockito.exceptions.verification.TooManyActualInvocations; import org.mockitoutil.TestBase; import javax.net.SocketFactory; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.net.Socket; import java.util.List; import java.util.Locale; import static junit.framework.TestCase.*; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.*; 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 {} @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()); } Person person = mock(Person.class, RETURNS_DEEP_STUBS); @Test public void shouldStubbingBasicallyWorkFine() throws Exception { //given given(person.getAddress().getStreet().getName()).willReturn("Norymberska"); //when String street = person.getAddress().getStreet().getName(); //then assertEquals("Norymberska", street); } @Test public void shouldVerificationBasicallyWorkFine() throws Exception { //given person.getAddress().getStreet().getName(); //then verify(person.getAddress().getStreet()).getName(); } @Test public void verification_work_with_argument_Matchers_in_nested_calls() throws Exception { //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() throws Exception { 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() throws Exception { 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), atMost(1)).getName(); } @Test public void inOrder_only_work_on_the_very_last_mock_but_it_works() throws Exception { 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() throws Exception { // 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) { Assertions.assertThat(e.getMessage()) .contains("Wanted 1 time") .contains("But was 3 times"); } } @Test public void shouldFailGracefullyWhenClassIsFinal() throws Exception { //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)); } }