• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
20 
21 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
22 import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
23 
24 import org.junit.AssumptionViolatedException;
25 import org.junit.rules.TestRule;
26 import org.junit.rules.TestWatcher;
27 import org.junit.runner.Description;
28 import org.junit.runners.model.Statement;
29 import org.mockito.quality.Strictness;
30 
31 import java.util.function.Supplier;
32 
33 /**
34  * <p>StaticMockFixtureRule is a {@link TestRule} that wraps one or more {@link StaticMockFixture}s
35  * to set them up and tear it down automatically. This works well when you have no other static
36  * mocks than the ones supported by their respective {@link StaticMockFixture}s.</p>
37  *
38  * <p>StaticMockFixtureRule should be defined as a rule on your test so it can clean up after
39  * itself. Like the following:</p>
40  * <pre class="prettyprint">
41 *  public final StaticMockFixture mStaticMockFixtures = ...;
42  * &#064;Rule
43  * public final StaticMockFixtureRule mStaticMockFixtureRule =
44  *     new StaticMockFixtureRule(mStaticMockFixtures);
45  * </pre>
46  */
47 public class StaticMockFixtureRule implements TestRule {
48     private StaticMockitoSession mMockitoSession;
49     private StaticMockFixture[] mStaticMockFixtures;
50     private Supplier<? extends StaticMockFixture>[] mSupplier;
51 
52     /**
53      * Constructs a StaticMockFixtureRule that always uses the same {@link StaticMockFixture}
54      * instance(s).
55      *
56      * @param staticMockFixtures the {@link StaticMockFixture}(s) to use.
57      */
StaticMockFixtureRule(StaticMockFixture... staticMockFixtures)58     public StaticMockFixtureRule(StaticMockFixture... staticMockFixtures) {
59         mStaticMockFixtures = staticMockFixtures;
60         mSupplier = null;
61     }
62 
63     /**
64      * Constructs a StaticMockFixtureRule that retrieves a new {@link StaticMockFixture} instance
65      * from one or more {@link Supplier<? extends   StaticMockFixture  >}s for each test invocation.
66      *
67      * @param supplier the {@link Supplier<? extends   StaticMockFixture  >}(s) that will supply the
68      * {@link StaticMockFixture}(s).
69      */
70     @SafeVarargs
StaticMockFixtureRule(Supplier<? extends StaticMockFixture>.... supplier)71     public StaticMockFixtureRule(Supplier<? extends StaticMockFixture>... supplier) {
72         mStaticMockFixtures = null;
73         mSupplier = supplier;
74     }
75 
76     @Override
apply(Statement base, Description description)77     public Statement apply(Statement base, Description description) {
78         StaticMockitoSessionBuilder sessionBuilder = getSessionBuilder();
79 
80         if (mSupplier != null) {
81             mStaticMockFixtures = new StaticMockFixture[mSupplier.length];
82             for (int i = 0; i < mSupplier.length; i++) {
83                 mStaticMockFixtures[i] = mSupplier[i].get();
84             }
85         }
86 
87         for (int i = 0; i < mStaticMockFixtures.length; i++) {
88             sessionBuilder = mStaticMockFixtures[i].setUpMockedClasses(sessionBuilder);
89         }
90 
91         mMockitoSession = sessionBuilder.startMocking();
92 
93         for (int i = 0; i < mStaticMockFixtures.length; i++) {
94             mStaticMockFixtures[i].setUpMockBehaviors();
95         }
96 
97         return new TestWatcher() {
98             @Override
99             protected void succeeded(Description description) {
100                 tearDown(null);
101             }
102 
103             @Override
104             protected void skipped(AssumptionViolatedException e, Description description) {
105                 tearDown(e);
106             }
107 
108             @Override
109             protected void failed(Throwable e, Description description) {
110                 tearDown(e);
111             }
112         }.apply(base, description);
113     }
114 
115     /**
116      * This allows overriding the creation of the builder for a new {@link StaticMockitoSession}.
117      * Mainly for testing, but also useful if you have other requirements for the session.
118      *
119      * @return a new {@link StaticMockitoSessionBuilder}.
120      */
121     public StaticMockitoSessionBuilder getSessionBuilder() {
122         return mockitoSession().strictness(Strictness.LENIENT);
123     }
124 
125     private void tearDown(Throwable e) {
126         mMockitoSession.finishMocking(e);
127 
128         for (int i = mStaticMockFixtures.length - 1; i >= 0; i--) {
129             mStaticMockFixtures[i].tearDown();
130             if (mSupplier != null) {
131                 mStaticMockFixtures[i] = null;
132             }
133         }
134 
135         if (mSupplier != null) {
136             mStaticMockFixtures = null;
137         }
138 
139         mMockitoSession = null;
140     }
141 }
142