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.debugging; 6 7 import org.assertj.core.api.Condition; 8 import org.junit.Test; 9 import org.mockito.InOrder; 10 import org.mockito.invocation.DescribedInvocation; 11 import org.mockito.listeners.InvocationListener; 12 import org.mockito.listeners.MethodInvocationReport; 13 14 import java.util.ArrayList; 15 import java.util.List; 16 17 import static org.assertj.core.api.Assertions.assertThat; 18 import static org.junit.Assert.fail; 19 import static org.mockito.BDDMockito.given; 20 import static org.mockito.BDDMockito.willReturn; 21 import static org.mockito.Mockito.any; 22 import static org.mockito.Mockito.doThrow; 23 import static org.mockito.Mockito.inOrder; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.withSettings; 26 27 28 /** 29 * Ensures that custom listeners can be registered and will be called every time 30 * a method on a mock is invoked. 31 */ 32 public class InvocationListenerCallbackTest { 33 34 @Test 35 public void should_call_single_listener_when_mock_return_normally() throws Exception { 36 // given 37 RememberingListener listener = new RememberingListener(); 38 Foo foo = mock(Foo.class, withSettings().invocationListeners(listener)); 39 willReturn("basil").given(foo).giveMeSomeString("herb"); 40 41 // when 42 foo.giveMeSomeString("herb"); 43 44 // then 45 assertThat(listener).is(notifiedFor("basil", getClass().getSimpleName())); 46 } 47 48 @Test 49 public void should_call_listeners_in_order() throws Exception { 50 // given 51 List<InvocationListener> container = new ArrayList<InvocationListener>(); 52 RememberingListener listener1 = new RememberingListener(container); 53 RememberingListener listener2 = new RememberingListener(container); 54 55 Foo foo = mock(Foo.class, withSettings().invocationListeners(listener1, listener2)); 56 57 // when 58 foo.giveMeSomeString("herb"); 59 60 // then 61 assertThat(container).containsExactly(listener1, listener2); 62 } 63 64 @Test 65 public void should_allow_same_listener() throws Exception { 66 // given 67 List<InvocationListener> container = new ArrayList<InvocationListener>(); 68 RememberingListener listener1 = new RememberingListener(container); 69 70 Foo foo = mock(Foo.class, withSettings().invocationListeners(listener1, listener1)); 71 72 // when 73 foo.giveMeSomeString("a"); 74 foo.giveMeSomeString("b"); 75 76 // then each listener was notified 2 times (notified 4 times in total) 77 assertThat(container).containsExactly(listener1, listener1, listener1, listener1); 78 } 79 80 @Test 81 public void should_call_all_listener_when_mock_return_normally() throws Exception { 82 // given 83 RememberingListener listener1 = new RememberingListener(); 84 RememberingListener listener2 = new RememberingListener(); 85 Foo foo = mock(Foo.class, withSettings().invocationListeners(listener1, listener2)); 86 given(foo.giveMeSomeString("herb")).willReturn("rosemary"); 87 88 // when 89 foo.giveMeSomeString("herb"); 90 91 // then 92 assertThat(listener1).is(notifiedFor("rosemary", getClass().getSimpleName())); 93 assertThat(listener2).is(notifiedFor("rosemary", getClass().getSimpleName())); 94 } 95 96 @Test 97 public void should_call_all_listener_when_mock_throws_exception() throws Exception { 98 // given 99 InvocationListener listener1 = mock(InvocationListener.class, "listener1"); 100 InvocationListener listener2 = mock(InvocationListener.class, "listener2"); 101 Foo foo = mock(Foo.class, withSettings().invocationListeners(listener1, listener2)); 102 doThrow(new OvenNotWorking()).when(foo).doSomething("cook"); 103 104 // when 105 try { 106 foo.doSomething("cook"); 107 fail("Exception expected."); 108 } catch (OvenNotWorking actualException) { 109 // then 110 InOrder orderedVerify = inOrder(listener1, listener2); 111 orderedVerify.verify(listener1).reportInvocation(any(MethodInvocationReport.class)); 112 orderedVerify.verify(listener2).reportInvocation(any(MethodInvocationReport.class)); 113 } 114 } 115 116 private static Condition<RememberingListener> notifiedFor(final Object returned, final String location) { 117 return new Condition<RememberingListener>() { 118 public boolean matches(RememberingListener toBeAsserted) { 119 assertThat(toBeAsserted.returnValue).isEqualTo(returned); 120 assertThat(toBeAsserted.invocation).isNotNull(); 121 assertThat(toBeAsserted.locationOfStubbing).contains(location); 122 return true; 123 } 124 }; 125 } 126 127 private static class RememberingListener implements InvocationListener { 128 private final List<InvocationListener> listenerContainer; 129 DescribedInvocation invocation; 130 Object returnValue; 131 String locationOfStubbing; 132 133 RememberingListener(List<InvocationListener> listenerContainer) { 134 this.listenerContainer = listenerContainer; 135 } 136 137 RememberingListener() { 138 this(new ArrayList<InvocationListener>()); 139 } 140 141 public void reportInvocation(MethodInvocationReport mcr) { 142 this.invocation = mcr.getInvocation(); 143 this.returnValue = mcr.getReturnedValue(); 144 this.locationOfStubbing = mcr.getLocationOfStubbing(); 145 listenerContainer.add(this); //so that we can assert on order 146 } 147 } 148 149 private static class OvenNotWorking extends RuntimeException { } 150 } 151