1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.modules.utils.testing; 18 19 import static org.junit.Assert.fail; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.Mockito.doNothing; 22 import static org.mockito.Mockito.doThrow; 23 import static org.mockito.Mockito.inOrder; 24 import static org.mockito.Mockito.verifyNoMoreInteractions; 25 import static org.mockito.Mockito.when; 26 import static org.mockito.quality.Strictness.LENIENT; 27 28 import androidx.test.filters.SmallTest; 29 import androidx.test.runner.AndroidJUnit4; 30 31 import com.android.dx.mockito.inline.extended.StaticMockitoSession; 32 import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; 33 34 import org.junit.After; 35 import org.junit.AssumptionViolatedException; 36 import org.junit.Before; 37 import org.junit.Test; 38 import org.junit.runner.Description; 39 import org.junit.runner.RunWith; 40 import org.junit.runners.model.Statement; 41 import org.mockito.InOrder; 42 import org.mockito.Mock; 43 import org.mockito.Mockito; 44 import org.mockito.MockitoSession; 45 46 import java.util.function.Supplier; 47 48 /** Tests that StaticMockFixture manages fixtures and suppliers correctly. */ 49 @RunWith(AndroidJUnit4.class) 50 @SmallTest 51 public class StaticMockFixtureRuleTest { 52 private MockitoSession mMockitoSession; 53 54 @Mock private StaticMockitoSessionBuilder mSessionBuilder; 55 @Mock private StaticMockitoSession mSession; 56 @Mock private StaticMockFixture mA1; 57 @Mock private StaticMockFixture mB1; 58 @Mock private StaticMockFixture mA2; 59 @Mock private StaticMockFixture mB2; 60 @Mock private Supplier<StaticMockFixture> mSupplyA; 61 @Mock private Supplier<StaticMockFixture> mSupplyB; 62 @Mock private Statement mStatement; 63 @Mock private Statement mSkipStatement; 64 @Mock private Statement mThrowStatement; 65 @Mock private Description mDescription; 66 67 @Before setUp()68 public void setUp() throws Throwable { 69 mMockitoSession = Mockito.mockitoSession() 70 .strictness(LENIENT) 71 .initMocks(this) 72 .startMocking(); 73 prepareMockBehaviours(); 74 } 75 76 @After tearDown()77 public void tearDown() { 78 mMockitoSession.finishMocking(); 79 } 80 prepareFixtureMocks(StaticMockFixture... mocks)81 private void prepareFixtureMocks(StaticMockFixture... mocks) { 82 for (StaticMockFixture mock : mocks) { 83 when(mock.setUpMockedClasses(any())).thenAnswer( 84 invocation -> invocation.getArgument(0)); 85 doNothing().when(mock).setUpMockBehaviors(); 86 } 87 } 88 prepareMockBehaviours()89 private void prepareMockBehaviours() throws Throwable { 90 when(mSessionBuilder.startMocking()).thenReturn(mSession); 91 when(mSupplyA.get()).thenReturn(mA1, mA2); 92 when(mSupplyB.get()).thenReturn(mB1, mB2); 93 prepareFixtureMocks(mA1, mA2, mB1, mB2); 94 when(mA1.setUpMockedClasses(any())).thenAnswer(invocation -> invocation.getArgument(0)); 95 doNothing().when(mA1).setUpMockBehaviors(); 96 when(mB1.setUpMockedClasses(any())).thenAnswer(invocation -> invocation.getArgument(0)); 97 doNothing().when(mB1).setUpMockBehaviors(); 98 doNothing().when(mStatement).evaluate(); 99 doThrow(new AssumptionViolatedException("bad assumption, test should be skipped")) 100 .when(mSkipStatement).evaluate(); 101 doThrow(new IllegalArgumentException("bad argument, test should be failed")) 102 .when(mThrowStatement).evaluate(); 103 doNothing().when(mA1).tearDown(); 104 doNothing().when(mB1).tearDown(); 105 } 106 mocksInOrder()107 private InOrder mocksInOrder() { 108 return inOrder(mSessionBuilder, mSession, mSupplyA, mSupplyB, mA1, mA2, mB1, mB2, 109 mStatement, mSkipStatement, mThrowStatement, mDescription); 110 } 111 verifyNoMoreImportantMockInteractions()112 private void verifyNoMoreImportantMockInteractions() { 113 verifyNoMoreInteractions(mSupplyA, mSupplyB, mA1, mA2, mB1, mB2, mStatement, 114 mSkipStatement, mThrowStatement); 115 } 116 117 @Test testRuleWorksWithExplicitFixtures()118 public void testRuleWorksWithExplicitFixtures() throws Throwable { 119 InOrder inOrder = mocksInOrder(); 120 121 StaticMockFixtureRule rule = new StaticMockFixtureRule(mA1, mB1) { 122 @Override public StaticMockitoSessionBuilder getSessionBuilder() { 123 return mSessionBuilder; 124 } 125 }; 126 Statement runMe = rule.apply(mStatement, mDescription); 127 128 inOrder.verify(mA1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 129 inOrder.verify(mB1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 130 inOrder.verify(mA1).setUpMockBehaviors(); 131 inOrder.verify(mB1).setUpMockBehaviors(); 132 133 runMe.evaluate(); 134 135 inOrder.verify(mStatement).evaluate(); 136 // note: tearDown in reverse order 137 inOrder.verify(mB1).tearDown(); 138 inOrder.verify(mA1).tearDown(); 139 140 // Round two: use the same fixtures again. 141 rule.apply(mStatement, mDescription).evaluate(); 142 143 inOrder.verify(mA1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 144 inOrder.verify(mB1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 145 inOrder.verify(mA1).setUpMockBehaviors(); 146 inOrder.verify(mB1).setUpMockBehaviors(); 147 inOrder.verify(mStatement).evaluate(); 148 // note: tearDown in reverse order 149 inOrder.verify(mB1).tearDown(); 150 inOrder.verify(mA1).tearDown(); 151 152 verifyNoMoreImportantMockInteractions(); 153 } 154 155 @Test testRuleWorksWithFixtureSuppliers()156 public void testRuleWorksWithFixtureSuppliers() throws Throwable { 157 InOrder inOrder = mocksInOrder(); 158 159 StaticMockFixtureRule rule = new StaticMockFixtureRule(mSupplyA, mSupplyB) { 160 @Override public StaticMockitoSessionBuilder getSessionBuilder() { 161 return mSessionBuilder; 162 } 163 }; 164 Statement runMe = rule.apply(mStatement, mDescription); 165 166 inOrder.verify(mSupplyA).get(); 167 inOrder.verify(mSupplyB).get(); 168 inOrder.verify(mA1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 169 inOrder.verify(mB1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 170 inOrder.verify(mA1).setUpMockBehaviors(); 171 inOrder.verify(mB1).setUpMockBehaviors(); 172 173 runMe.evaluate(); 174 175 inOrder.verify(mStatement).evaluate(); 176 // note: tearDown in reverse order 177 inOrder.verify(mB1).tearDown(); 178 inOrder.verify(mA1).tearDown(); 179 180 // Round two: use the same suppliers again to retrieve different fixtures: mA2 and mB2 181 rule.apply(mStatement, mDescription).evaluate(); 182 183 inOrder.verify(mSupplyA).get(); 184 inOrder.verify(mSupplyB).get(); 185 inOrder.verify(mA2).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 186 inOrder.verify(mB2).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 187 inOrder.verify(mA2).setUpMockBehaviors(); 188 inOrder.verify(mB2).setUpMockBehaviors(); 189 inOrder.verify(mStatement).evaluate(); 190 // note: tearDown in reverse order 191 inOrder.verify(mB2).tearDown(); 192 inOrder.verify(mA2).tearDown(); 193 194 verifyNoMoreImportantMockInteractions(); 195 } 196 197 @Test testTearDownOnSkippedTests()198 public void testTearDownOnSkippedTests() throws Throwable { 199 InOrder inOrder = mocksInOrder(); 200 201 StaticMockFixtureRule rule = new StaticMockFixtureRule(mA1, mB1) { 202 @Override public StaticMockitoSessionBuilder getSessionBuilder() { 203 return mSessionBuilder; 204 } 205 }; 206 Statement skipStatement = rule.apply(mSkipStatement, mDescription); 207 208 inOrder.verify(mA1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 209 inOrder.verify(mB1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 210 inOrder.verify(mA1).setUpMockBehaviors(); 211 inOrder.verify(mB1).setUpMockBehaviors(); 212 213 try { 214 skipStatement.evaluate(); 215 fail("AssumptionViolatedException should have been thrown"); 216 } catch (AssumptionViolatedException e) { 217 // expected 218 } 219 220 inOrder.verify(mSkipStatement).evaluate(); 221 // note: tearDown in reverse order 222 inOrder.verify(mB1).tearDown(); 223 inOrder.verify(mA1).tearDown(); 224 225 verifyNoMoreImportantMockInteractions(); 226 } 227 228 @Test testTearDownOnFailedTests()229 public void testTearDownOnFailedTests() throws Throwable { 230 InOrder inOrder = mocksInOrder(); 231 232 StaticMockFixtureRule rule = new StaticMockFixtureRule(mA1, mB1) { 233 @Override public StaticMockitoSessionBuilder getSessionBuilder() { 234 return mSessionBuilder; 235 } 236 }; 237 Statement failStatement = rule.apply(mThrowStatement, mDescription); 238 239 inOrder.verify(mA1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 240 inOrder.verify(mB1).setUpMockedClasses(any(StaticMockitoSessionBuilder.class)); 241 inOrder.verify(mA1).setUpMockBehaviors(); 242 inOrder.verify(mB1).setUpMockBehaviors(); 243 244 try { 245 failStatement.evaluate(); 246 fail("IllegalArgumentException should have been thrown"); 247 } catch (IllegalArgumentException e) { 248 // expected 249 } 250 251 inOrder.verify(mThrowStatement).evaluate(); 252 // note: tearDown in reverse order 253 inOrder.verify(mB1).tearDown(); 254 inOrder.verify(mA1).tearDown(); 255 256 verifyNoMoreImportantMockInteractions(); 257 } 258 } 259