/
UniversalTestListener.java
125 lines (109 loc) · 4.96 KB
/
UniversalTestListener.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
* Copyright (c) 2018 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.junit;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.mockito.MockedStatic;
import org.mockito.internal.creation.settings.CreationSettings;
import org.mockito.internal.listeners.AutoCleanableListener;
import org.mockito.mock.MockCreationSettings;
import org.mockito.plugins.MockitoLogger;
import org.mockito.quality.Strictness;
/**
* Universal test listener that behaves accordingly to current setting of strictness.
* Will come handy when we offer tweaking strictness at the method level with annotation.
* Should be relatively easy to improve and offer tweaking strictness per mock.
*/
public class UniversalTestListener implements MockitoTestListener, AutoCleanableListener {
private Strictness currentStrictness;
private final MockitoLogger logger;
private Map<Object, MockCreationSettings> mocks =
new IdentityHashMap<Object, MockCreationSettings>();
private DefaultStubbingLookupListener stubbingLookupListener;
private boolean listenerDirty;
public UniversalTestListener(Strictness initialStrictness, MockitoLogger logger) {
this.currentStrictness = initialStrictness;
this.logger = logger;
// creating single stubbing lookup listener per junit rule instance / test method
// this way, when strictness is updated in the middle of the test it will affect the
// behavior of the stubbing listener
this.stubbingLookupListener = new DefaultStubbingLookupListener(currentStrictness);
}
@Override
public void testFinished(TestFinishedEvent event) {
Collection<Object> createdMocks = mocks.keySet();
// At this point, we don't need the mocks any more and we can mark all collected mocks for
// gc
// TODO make it better, it's easy to forget to clean up mocks and we still create new
// instance of list that nobody will read, it's also duplicated
// TODO clean up all other state, null out stubbingLookupListener
mocks = new IdentityHashMap<Object, MockCreationSettings>();
switch (currentStrictness) {
case WARN:
emitWarnings(logger, event, createdMocks);
break;
case STRICT_STUBS:
reportUnusedStubs(event, createdMocks);
break;
case LENIENT:
break;
default:
throw new IllegalStateException("Unknown strictness: " + currentStrictness);
}
}
private void reportUnusedStubs(TestFinishedEvent event, Collection<Object> mocks) {
// If there is some other failure (or mismatches were detected) don't report another
// exception to avoid confusion
if (event.getFailure() == null && !stubbingLookupListener.isMismatchesReported()) {
UnusedStubbings unused = new UnusedStubbingsFinder().getUnusedStubbings(mocks);
unused.reportUnused();
}
}
private static void emitWarnings(
MockitoLogger logger, TestFinishedEvent event, Collection<Object> mocks) {
if (event.getFailure() != null) {
// print stubbing mismatches only when there is a test failure
// to avoid false negatives. Give hint only when test fails.
new ArgMismatchFinder()
.getStubbingArgMismatches(mocks)
.format(event.getTestName(), logger);
} else {
// print unused stubbings only when test succeeds to avoid reporting multiple problems
// and confusing users
new UnusedStubbingsFinder()
.getUnusedStubbings(mocks)
.format(event.getTestName(), logger);
}
}
@Override
public void onMockCreated(Object mock, MockCreationSettings settings) {
this.mocks.put(mock, settings);
// It is not ideal that we modify the state of MockCreationSettings object
// MockCreationSettings is intended to be an immutable view of the creation settings
// In future, we should start passing MockSettings object to the creation listener
// TODO #793 - when completed, we should be able to get rid of the CreationSettings casting
// below
((CreationSettings) settings).getStubbingLookupListeners().add(stubbingLookupListener);
}
public void setStrictness(Strictness strictness) {
this.currentStrictness = strictness;
this.stubbingLookupListener.setCurrentStrictness(strictness);
}
/**
* See {@link AutoCleanableListener#isListenerDirty()}
*/
@Override
public boolean isListenerDirty() {
return listenerDirty;
}
/**
* Marks listener as dirty, scheduled for cleanup when the next session starts
*/
public void setListenerDirty() {
this.listenerDirty = true;
}
}