1/*
2 * Copyright (c) 2007 Mockito contributors
3 * This program is made available under the terms of the MIT License.
4 */
5package org.mockitousage.debugging;
6
7import org.assertj.core.api.Assertions;
8import org.junit.After;
9import org.junit.Before;
10import org.junit.Test;
11import org.junit.runner.RunWith;
12import org.mockito.Mock;
13import org.mockito.internal.util.MockUtil;
14import org.mockito.junit.MockitoJUnitRunner;
15
16import java.io.ByteArrayOutputStream;
17import java.io.PrintStream;
18
19import static org.junit.Assert.fail;
20import static org.mockito.BDDMockito.given;
21import static org.mockito.Mockito.*;
22
23/**
24 * Tests the verbose logging of invocation on mock methods.
25 *
26 * BEWARE: These tests rely on mocking the standard output. While in a
27 * single-threaded environment the Before/After-contract ensures, that the
28 * original output stream is restored, there is no guarantee for this
29 * in the parallel setting.
30 * Maybe, the test class should be @Ignore'd by default ...
31 */
32@RunWith(MockitoJUnitRunner.class)
33public class VerboseLoggingOfInvocationsOnMockTest {
34
35    private ByteArrayOutputStream output;
36    private PrintStream original;
37
38    @Mock UnrelatedClass unrelatedMock;
39
40    @Before
41    public void setUp() {
42        original = System.out;
43        output = new ByteArrayOutputStream();
44        System.setOut(new PrintStream(output));
45    }
46
47    @After
48    public void tearDown() {
49        System.setOut(original);
50    }
51
52    @Test
53    public void shouldNotPrintInvocationOnMockWithoutSetting() {
54        // given
55        Foo foo = mock(Foo.class, withSettings().verboseLogging());
56
57        // when
58        foo.giveMeSomeString("Klipsch");
59        unrelatedMock.unrelatedMethod("Apple");
60
61        // then
62        Assertions.assertThat(printed())
63                .doesNotContain(mockName(unrelatedMock))
64                .doesNotContain("unrelatedMethod")
65                .doesNotContain("Apple");
66    }
67
68    @Test
69    public void shouldPrintUnstubbedInvocationOnMockToStdOut() {
70        // given
71        Foo foo = mock(Foo.class, withSettings().verboseLogging());
72
73        // when
74        foo.doSomething("Klipsch");
75
76        // then
77        Assertions.assertThat(printed())
78                .contains(getClass().getName())
79                .contains(mockName(foo))
80                .contains("doSomething")
81                .contains("Klipsch");
82    }
83
84    @Test
85    public void shouldPrintStubbedInvocationOnMockToStdOut() {
86        // given
87        Foo foo = mock(Foo.class, withSettings().verboseLogging());
88        given(foo.giveMeSomeString("Klipsch")).willReturn("earbuds");
89
90        // when
91        foo.giveMeSomeString("Klipsch");
92
93        // then
94        Assertions.assertThat(printed())
95                .contains(getClass().getName())
96                .contains(mockName(foo))
97                .contains("giveMeSomeString")
98                .contains("Klipsch")
99                .contains("earbuds");
100    }
101
102    @Test
103    public void shouldPrintThrowingInvocationOnMockToStdOut() {
104        // given
105        Foo foo = mock(Foo.class, withSettings().verboseLogging());
106        doThrow(new ThirdPartyException()).when(foo).doSomething("Klipsch");
107
108        try {
109            // when
110            foo.doSomething("Klipsch");
111            fail("Exception excepted.");
112        } catch (ThirdPartyException e) {
113            // then
114            Assertions.assertThat(printed())
115                    .contains(getClass().getName())
116                    .contains(mockName(foo))
117                    .contains("doSomething")
118                    .contains("Klipsch")
119                    .contains(ThirdPartyException.class.getName());
120        }
121    }
122
123    @Test
124    public void shouldPrintRealInvocationOnSpyToStdOut() {
125        // given
126        FooImpl fooSpy = mock(FooImpl.class,
127                withSettings().spiedInstance(new FooImpl()).verboseLogging());
128        doCallRealMethod().when(fooSpy).doSomething("Klipsch");
129
130        // when
131        fooSpy.doSomething("Klipsch");
132
133        // then
134        Assertions.assertThat(printed())
135                .contains(getClass().getName())
136                .contains(mockName(fooSpy))
137                .contains("doSomething")
138                .contains("Klipsch");
139    }
140
141    @Test
142    public void usage() {
143        // given
144        Foo foo = mock(Foo.class, withSettings().verboseLogging());
145        given(foo.giveMeSomeString("Apple")).willReturn(
146                "earbuds");
147
148        // when
149        foo.giveMeSomeString("Shure");
150        foo.giveMeSomeString("Apple");
151        foo.doSomething("Klipsch");
152    }
153
154    private String printed() {
155        return output.toString();
156    }
157
158    private String mockName(Object mock) {
159        return MockUtil.getMockName(mock).toString();
160    }
161
162    private static class UnrelatedClass {
163        void unrelatedMethod(String anotherStringValue) {
164        }
165    }
166
167    /**
168     * An exception that isn't defined by Mockito or the JDK and therefore does
169     * not appear in the logging result by chance alone.
170     */
171    static class ThirdPartyException extends RuntimeException {
172        private static final long serialVersionUID = 2160445705646210847L;
173    }
174
175    static class FooImpl implements Foo {
176        public String giveMeSomeString(String param) {
177            return null;
178        }
179
180        public void doSomething(String param) {
181        }
182    }
183}
184