Home | History | Annotate | Download | only in stubbing
      1 /*
      2  * Copyright (c) 2007 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockitousage.stubbing;
      6 
      7 import org.assertj.core.api.Assertions;
      8 import org.junit.Test;
      9 import org.mockito.InOrder;
     10 import org.mockito.exceptions.verification.TooManyActualInvocations;
     11 import org.mockitoutil.TestBase;
     12 
     13 import javax.net.SocketFactory;
     14 import java.io.ByteArrayOutputStream;
     15 import java.io.OutputStream;
     16 import java.net.Socket;
     17 import java.util.List;
     18 import java.util.Locale;
     19 
     20 import static org.junit.Assert.*;
     21 import static org.mockito.BDDMockito.given;
     22 import static org.mockito.Mockito.*;
     23 
     24 
     25 public class DeepStubbingTest extends TestBase {
     26 
     27     static class Person {
     28         Address address;
     29 
     30         public Address getAddress() {
     31             return address;
     32         }
     33 
     34         public Address getAddress(String addressName) {
     35             return address;
     36         }
     37 
     38         public FinalClass getFinalClass() {
     39             return null;
     40         }
     41     }
     42 
     43     static class Address {
     44         Street street;
     45 
     46         public Street getStreet() {
     47             return street;
     48         }
     49 
     50         public Street getStreet(Locale locale) {
     51             return street;
     52         }
     53     }
     54 
     55     static class Street {
     56         String name;
     57 
     58         public String getName() {
     59             return name;
     60         }
     61 
     62         public String getLongName() {
     63             return name;
     64         }
     65     }
     66 
     67     static final class FinalClass {}
     68 
     69     interface First {
     70         Second getSecond();
     71 
     72         String getString();
     73     }
     74 
     75     interface Second extends List<String> {}
     76 
     77     @Test
     78     public void myTest() throws Exception {
     79         SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS);
     80         when(sf.createSocket(anyString(), eq(80))).thenReturn(null);
     81         sf.createSocket("what", 80);
     82     }
     83 
     84     @Test
     85     public void simpleCase() throws Exception {
     86         OutputStream out = new ByteArrayOutputStream();
     87         Socket socket = mock(Socket.class);
     88         when(socket.getOutputStream()).thenReturn(out);
     89 
     90         assertSame(out, socket.getOutputStream());
     91     }
     92 
     93     /**
     94      * Test that deep stubbing works for one intermediate level
     95      */
     96     @Test
     97     public void oneLevelDeep() throws Exception {
     98         OutputStream out = new ByteArrayOutputStream();
     99 
    100         SocketFactory socketFactory = mock(SocketFactory.class, RETURNS_DEEP_STUBS);
    101         when(socketFactory.createSocket().getOutputStream()).thenReturn(out);
    102 
    103         assertSame(out, socketFactory.createSocket().getOutputStream());
    104     }
    105 
    106     /**
    107      * Test that stubbing of two mocks stubs don't interfere
    108      */
    109     @Test
    110     public void interactions() throws Exception {
    111         OutputStream out1 = new ByteArrayOutputStream();
    112         OutputStream out2 = new ByteArrayOutputStream();
    113 
    114         SocketFactory sf1 = mock(SocketFactory.class, RETURNS_DEEP_STUBS);
    115         when(sf1.createSocket().getOutputStream()).thenReturn(out1);
    116 
    117         SocketFactory sf2 = mock(SocketFactory.class, RETURNS_DEEP_STUBS);
    118         when(sf2.createSocket().getOutputStream()).thenReturn(out2);
    119 
    120         assertSame(out1, sf1.createSocket().getOutputStream());
    121         assertSame(out2, sf2.createSocket().getOutputStream());
    122     }
    123 
    124     /**
    125      * Test that stubbing of methods of different arguments don't interfere
    126      */
    127     @Test
    128     public void withArguments() throws Exception {
    129         OutputStream out1 = new ByteArrayOutputStream();
    130         OutputStream out2 = new ByteArrayOutputStream();
    131         OutputStream out3 = new ByteArrayOutputStream();
    132 
    133         SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS);
    134         when(sf.createSocket().getOutputStream()).thenReturn(out1);
    135         when(sf.createSocket("google.com", 80).getOutputStream()).thenReturn(out2);
    136         when(sf.createSocket("stackoverflow.com", 80).getOutputStream()).thenReturn(out3);
    137 
    138         assertSame(out1, sf.createSocket().getOutputStream());
    139         assertSame(out2, sf.createSocket("google.com", 80).getOutputStream());
    140         assertSame(out3, sf.createSocket("stackoverflow.com", 80).getOutputStream());
    141     }
    142 
    143     /**
    144      * Test that deep stubbing work with argument patterns
    145      */
    146     @Test
    147     public void withAnyPatternArguments() throws Exception {
    148         OutputStream out = new ByteArrayOutputStream();
    149 
    150         //TODO: should not use javax in case it changes
    151         SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS);
    152         when(sf.createSocket(anyString(), anyInt()).getOutputStream()).thenReturn(out);
    153 
    154         assertSame(out, sf.createSocket("google.com", 80).getOutputStream());
    155         assertSame(out, sf.createSocket("stackoverflow.com", 8080).getOutputStream());
    156     }
    157 
    158     /**
    159      * Test that deep stubbing work with argument patterns
    160      */
    161     @Test
    162     public void withComplexPatternArguments() throws Exception {
    163         OutputStream out1 = new ByteArrayOutputStream();
    164         OutputStream out2 = new ByteArrayOutputStream();
    165 
    166         SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS);
    167         when(sf.createSocket(anyString(), eq(80)).getOutputStream()).thenReturn(out1);
    168         when(sf.createSocket(anyString(), eq(8080)).getOutputStream()).thenReturn(out2);
    169 
    170         assertSame(out2, sf.createSocket("stackoverflow.com", 8080).getOutputStream());
    171         assertSame(out1, sf.createSocket("google.com", 80).getOutputStream());
    172         assertSame(out2, sf.createSocket("google.com", 8080).getOutputStream());
    173         assertSame(out1, sf.createSocket("stackoverflow.com", 80).getOutputStream());
    174     }
    175 
    176     /**
    177      * Test that deep stubbing work with primitive expected values
    178      */
    179     @Test
    180     public void withSimplePrimitive() throws Exception {
    181         int a = 32;
    182 
    183         SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS);
    184         when(sf.createSocket().getPort()).thenReturn(a);
    185 
    186         assertEquals(a, sf.createSocket().getPort());
    187     }
    188 
    189     /**
    190      * Test that deep stubbing work with primitive expected values with
    191      * pattern method arguments
    192      */
    193     @Test
    194     public void withPatternPrimitive() throws Exception {
    195         int a = 12, b = 23, c = 34;
    196 
    197         SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS);
    198         when(sf.createSocket(eq("stackoverflow.com"), eq(80)).getPort()).thenReturn(a);
    199         when(sf.createSocket(eq("google.com"), anyInt()).getPort()).thenReturn(b);
    200         when(sf.createSocket(eq("stackoverflow.com"), eq(8080)).getPort()).thenReturn(c);
    201 
    202         assertEquals(b, sf.createSocket("google.com", 80).getPort());
    203         assertEquals(c, sf.createSocket("stackoverflow.com", 8080).getPort());
    204         assertEquals(a, sf.createSocket("stackoverflow.com", 80).getPort());
    205     }
    206 
    207     Person person = mock(Person.class, RETURNS_DEEP_STUBS);
    208 
    209     @Test
    210     public void shouldStubbingBasicallyWorkFine() throws Exception {
    211         //given
    212         given(person.getAddress().getStreet().getName()).willReturn("Norymberska");
    213 
    214         //when
    215         String street = person.getAddress().getStreet().getName();
    216 
    217         //then
    218         assertEquals("Norymberska", street);
    219     }
    220 
    221     @Test
    222     public void shouldVerificationBasicallyWorkFine() throws Exception {
    223         //given
    224         person.getAddress().getStreet().getName();
    225 
    226         //then
    227         verify(person.getAddress().getStreet()).getName();
    228     }
    229 
    230     @Test
    231     public void verification_work_with_argument_Matchers_in_nested_calls() throws Exception {
    232         //given
    233         person.getAddress("111 Mock Lane").getStreet();
    234         person.getAddress("111 Mock Lane").getStreet(Locale.ITALIAN).getName();
    235 
    236         //then
    237         verify(person.getAddress(anyString())).getStreet();
    238         verify(person.getAddress(anyString()).getStreet(Locale.CHINESE), never()).getName();
    239         verify(person.getAddress(anyString()).getStreet(eq(Locale.ITALIAN))).getName();
    240     }
    241 
    242     @Test
    243     public void deep_stub_return_same_mock_instance_if_invocation_matchers_matches() throws Exception {
    244         when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep");
    245 
    246         person.getAddress("the docks").getStreet().getName();
    247 
    248         assertSame(person.getAddress("the docks").getStreet(), person.getAddress(anyString()).getStreet());
    249         assertSame(person.getAddress(anyString()).getStreet(), person.getAddress(anyString()).getStreet());
    250         assertSame(person.getAddress("the docks").getStreet(), person.getAddress("the docks").getStreet());
    251         assertSame(person.getAddress(anyString()).getStreet(), person.getAddress("the docks").getStreet());
    252         assertSame(person.getAddress("111 Mock Lane").getStreet(), person.getAddress("the docks").getStreet());
    253     }
    254 
    255     @Test
    256     public void times_never_atLeast_atMost_verificationModes_should_work() throws Exception {
    257         when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep");
    258 
    259         person.getAddress("the docks").getStreet().getName();
    260         person.getAddress("the docks").getStreet().getName();
    261         person.getAddress("the docks").getStreet().getName();
    262         person.getAddress("the docks").getStreet(Locale.ITALIAN).getName();
    263 
    264         verify(person.getAddress("the docks").getStreet(), times(3)).getName();
    265         verify(person.getAddress("the docks").getStreet(Locale.CHINESE), never()).getName();
    266         verify(person.getAddress("the docks").getStreet(Locale.ITALIAN), atMost(1)).getName();
    267     }
    268 
    269 
    270     @Test
    271     public void inOrder_only_work_on_the_very_last_mock_but_it_works() throws Exception {
    272         when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep");
    273         when(person.getAddress(anyString()).getStreet(Locale.ITALIAN).getName()).thenReturn("deep");
    274         when(person.getAddress(anyString()).getStreet(Locale.CHINESE).getName()).thenReturn("deep");
    275 
    276         person.getAddress("the docks").getStreet().getName();
    277         person.getAddress("the docks").getStreet().getLongName();
    278         person.getAddress("the docks").getStreet(Locale.ITALIAN).getName();
    279         person.getAddress("the docks").getStreet(Locale.CHINESE).getName();
    280 
    281         InOrder inOrder = inOrder(
    282                 person.getAddress("the docks").getStreet(),
    283                 person.getAddress("the docks").getStreet(Locale.CHINESE),
    284                 person.getAddress("the docks").getStreet(Locale.ITALIAN)
    285         );
    286         inOrder.verify(person.getAddress("the docks").getStreet(), times(1)).getName();
    287         inOrder.verify(person.getAddress("the docks").getStreet()).getLongName();
    288         inOrder.verify(person.getAddress("the docks").getStreet(Locale.ITALIAN), atLeast(1)).getName();
    289         inOrder.verify(person.getAddress("the docks").getStreet(Locale.CHINESE)).getName();
    290     }
    291 
    292     @Test
    293     public void verificationMode_only_work_on_the_last_returned_mock() throws Exception {
    294         // 1st invocation on Address mock (stubbing)
    295         when(person.getAddress("the docks").getStreet().getName()).thenReturn("deep");
    296 
    297         // 2nd invocation on Address mock (real)
    298         person.getAddress("the docks").getStreet().getName();
    299         // 3rd invocation on Address mock (verification)
    300         // (Address mock is not in verification mode)
    301         verify(person.getAddress("the docks").getStreet()).getName();
    302 
    303         try {
    304             verify(person.getAddress("the docks"), times(1)).getStreet();
    305             fail();
    306         } catch (TooManyActualInvocations e) {
    307             Assertions.assertThat(e.getMessage())
    308                     .contains("Wanted 1 time")
    309                     .contains("But was 3 times");
    310         }
    311     }
    312 
    313     @Test
    314     public void shouldFailGracefullyWhenClassIsFinal() throws Exception {
    315         //when
    316         FinalClass value = new FinalClass();
    317         given(person.getFinalClass()).willReturn(value);
    318 
    319         //then
    320         assertEquals(value, person.getFinalClass());
    321     }
    322 
    323     @Test
    324     public void deep_stub_does_not_try_to_mock_generic_final_classes() {
    325         First first = mock(First.class, RETURNS_DEEP_STUBS);
    326         assertNull(first.getString());
    327         assertNull(first.getSecond().get(0));
    328     }
    329 }
    330