• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric;
2 
3 import static com.google.common.truth.Truth.assertThat;
4 import static java.util.Arrays.asList;
5 import static java.util.Collections.singletonList;
6 import static java.util.stream.Collectors.toSet;
7 import static org.junit.Assert.fail;
8 import static org.mockito.Mockito.mock;
9 import static org.robolectric.util.ReflectionHelpers.callConstructor;
10 
11 import android.app.Application;
12 import android.os.Build;
13 import java.lang.reflect.Method;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Set;
17 import javax.annotation.Nonnull;
18 import org.junit.After;
19 import org.junit.Before;
20 import org.junit.FixMethodOrder;
21 import org.junit.Ignore;
22 import org.junit.Test;
23 import org.junit.runner.Description;
24 import org.junit.runner.RunWith;
25 import org.junit.runner.notification.Failure;
26 import org.junit.runner.notification.RunListener;
27 import org.junit.runner.notification.RunNotifier;
28 import org.junit.runners.JUnit4;
29 import org.junit.runners.MethodSorters;
30 import org.junit.runners.model.InitializationError;
31 import org.robolectric.RobolectricTestRunner.ResourcesMode;
32 import org.robolectric.RobolectricTestRunner.RobolectricFrameworkMethod;
33 import org.robolectric.RobolectricTestRunnerTest.TestWithBrokenAppCreate.MyTestApplication;
34 import org.robolectric.android.internal.ParallelUniverse;
35 import org.robolectric.annotation.Config;
36 import org.robolectric.internal.ParallelUniverseInterface;
37 import org.robolectric.internal.SdkConfig;
38 import org.robolectric.internal.SdkEnvironment;
39 import org.robolectric.manifest.AndroidManifest;
40 import org.robolectric.util.PerfStatsCollector.Metric;
41 import org.robolectric.util.PerfStatsReporter;
42 import org.robolectric.util.TestUtil;
43 
44 @RunWith(JUnit4.class)
45 public class RobolectricTestRunnerTest {
46 
47   private RunNotifier notifier;
48   private List<String> events;
49   private String priorEnabledSdks;
50   private String priorAlwaysInclude;
51 
52   @Before
setUp()53   public void setUp() throws Exception {
54     notifier = new RunNotifier();
55     events = new ArrayList<>();
56     notifier.addListener(new RunListener() {
57       @Override
58       public void testIgnored(Description description) throws Exception {
59         events.add("ignored: " + description.getDisplayName());
60       }
61 
62       @Override
63       public void testFailure(Failure failure) throws Exception {
64         events.add("failure: " + failure.getMessage());
65       }
66     });
67 
68     priorEnabledSdks = System.getProperty("robolectric.enabledSdks");
69     System.clearProperty("robolectric.enabledSdks");
70 
71     priorAlwaysInclude = System.getProperty("robolectric.alwaysIncludeVariantMarkersInTestName");
72     System.clearProperty("robolectric.alwaysIncludeVariantMarkersInTestName");
73   }
74 
75   @After
tearDown()76   public void tearDown() throws Exception {
77     TestUtil.resetSystemProperty(
78         "robolectric.alwaysIncludeVariantMarkersInTestName", priorAlwaysInclude);
79     TestUtil.resetSystemProperty("robolectric.enabledSdks", priorEnabledSdks);
80   }
81 
82   @Test
ignoredTestCanSpecifyUnsupportedSdkWithoutExploding()83   public void ignoredTestCanSpecifyUnsupportedSdkWithoutExploding() throws Exception {
84     RobolectricTestRunner runner = new MyRobolectricTestRunner(TestWithOldSdk.class);
85     runner.run(notifier);
86     assertThat(events).containsExactly(
87         "failure: Robolectric does not support API level 11.",
88         "ignored: ignoredOldSdkMethod(org.robolectric.RobolectricTestRunnerTest$TestWithOldSdk)"
89     );
90   }
91 
92   @Test
failureInResetterDoesntBreakAllTests()93   public void failureInResetterDoesntBreakAllTests() throws Exception {
94     RobolectricTestRunner runner =
95         new MyRobolectricTestRunner(TestWithTwoMethods.class) {
96           @Override
97           ParallelUniverseInterface getHooksInterface(SdkEnvironment sdkEnvironment) {
98             Class<? extends ParallelUniverseInterface> clazz =
99                 sdkEnvironment.bootstrappedClass(MyParallelUniverseWithFailingSetUp.class);
100             return callConstructor(clazz);
101           }
102         };
103     runner.run(notifier);
104     assertThat(events).containsExactly(
105         "failure: fake error in setUpApplicationState",
106         "failure: fake error in setUpApplicationState"
107     );
108   }
109 
110   @Test
failureInAppOnCreateDoesntBreakAllTests()111   public void failureInAppOnCreateDoesntBreakAllTests() throws Exception {
112     RobolectricTestRunner runner = new MyRobolectricTestRunner(TestWithBrokenAppCreate.class);
113     runner.run(notifier);
114     System.out.println("events = " + events);
115     assertThat(events)
116         .containsExactly(
117             "failure: fake error in application.onCreate",
118             "failure: fake error in application.onCreate");
119   }
120 
121   @Test
equalityOfRobolectricFrameworkMethod()122   public void equalityOfRobolectricFrameworkMethod() throws Exception {
123     Method method = TestWithTwoMethods.class.getMethod("first");
124     RobolectricFrameworkMethod rfm16 =
125         new RobolectricFrameworkMethod(
126             method,
127             mock(AndroidManifest.class),
128             new SdkConfig(16),
129             mock(Config.class),
130             ResourcesMode.legacy,
131             ResourcesMode.legacy,
132             false);
133     RobolectricFrameworkMethod rfm17 =
134         new RobolectricFrameworkMethod(
135             method,
136             mock(AndroidManifest.class),
137             new SdkConfig(17),
138             mock(Config.class),
139             ResourcesMode.legacy,
140             ResourcesMode.legacy,
141             false);
142     RobolectricFrameworkMethod rfm16b =
143         new RobolectricFrameworkMethod(
144             method,
145             mock(AndroidManifest.class),
146             new SdkConfig(16),
147             mock(Config.class),
148             ResourcesMode.legacy,
149             ResourcesMode.legacy,
150             false);
151     RobolectricFrameworkMethod rfm16c =
152         new RobolectricFrameworkMethod(
153             method,
154             mock(AndroidManifest.class),
155             new SdkConfig(16),
156             mock(Config.class),
157             ResourcesMode.binary,
158             ResourcesMode.legacy,
159             false);
160 
161     assertThat(rfm16).isNotEqualTo(rfm17);
162     assertThat(rfm16).isEqualTo(rfm16b);
163     assertThat(rfm16).isNotEqualTo(rfm16c);
164 
165     assertThat(rfm16.hashCode()).isEqualTo((rfm16b.hashCode()));
166   }
167 
168   @Test
shouldReportPerfStats()169   public void shouldReportPerfStats() throws Exception {
170     List<Metric> metrics = new ArrayList<>();
171     PerfStatsReporter reporter = (metadata, metrics1) -> metrics.addAll(metrics1);
172 
173     RobolectricTestRunner runner = new MyRobolectricTestRunner(TestWithTwoMethods.class) {
174       @Nonnull
175       @Override
176       protected Iterable<PerfStatsReporter> getPerfStatsReporters() {
177         return singletonList(reporter);
178       }
179     };
180 
181     runner.run(notifier);
182 
183     Set<String> metricNames = metrics.stream().map(Metric::getName).collect(toSet());
184     assertThat(metricNames).contains("initialization");
185   }
186 
187   /////////////////////////////
188 
189   public static class MyParallelUniverseWithFailingSetUp extends ParallelUniverse {
190 
191     @Override
setUpApplicationState(ApkLoader apkLoader, Method method, Config config, AndroidManifest appManifest, SdkEnvironment environment)192     public void setUpApplicationState(ApkLoader apkLoader, Method method,
193         Config config, AndroidManifest appManifest, SdkEnvironment environment) {
194       throw new RuntimeException("fake error in setUpApplicationState");
195     }
196   }
197 
198   @Ignore
199   public static class TestWithOldSdk {
200     @Config(sdk = Build.VERSION_CODES.HONEYCOMB)
201     @Test
oldSdkMethod()202     public void oldSdkMethod() throws Exception {
203       fail("I should not be run!");
204     }
205 
206     @Ignore("This test shouldn't run, and shouldn't cause the test runner to fail")
207     @Config(sdk = Build.VERSION_CODES.HONEYCOMB)
208     @Test
ignoredOldSdkMethod()209     public void ignoredOldSdkMethod() throws Exception {
210       fail("I should not be run!");
211     }
212   }
213 
214   @Ignore
215   @FixMethodOrder(MethodSorters.NAME_ASCENDING)
216   public static class TestWithTwoMethods {
217     @Test
first()218     public void first() throws Exception {
219     }
220 
221     @Test
second()222     public void second() throws Exception {
223     }
224   }
225 
226   @Ignore
227   @FixMethodOrder(MethodSorters.NAME_ASCENDING)
228   @Config(application = MyTestApplication.class)
229   public static class TestWithBrokenAppCreate {
230     @Test
first()231     public void first() throws Exception {}
232 
233     @Test
second()234     public void second() throws Exception {}
235 
236     public static class MyTestApplication extends Application {
237       @Override
onCreate()238       public void onCreate() {
239         throw new RuntimeException("fake error in application.onCreate");
240       }
241     }
242   }
243 
244   @Ignore
245   @FixMethodOrder(MethodSorters.NAME_ASCENDING)
246   @Config(application = MyTestApplication.class)
247   public static class TestWithBrokenAppTerminate {
248     @Test
first()249     public void first() throws Exception {}
250 
251     @Test
second()252     public void second() throws Exception {}
253 
254     public static class MyTestApplication extends Application {
255       @Override
onTerminate()256       public void onTerminate() {
257         throw new RuntimeException("fake error in application.onTerminate");
258       }
259     }
260   }
261 
262   private static class MyRobolectricTestRunner extends RobolectricTestRunner {
MyRobolectricTestRunner(Class<?> testClass)263     public MyRobolectricTestRunner(Class<?> testClass) throws InitializationError {
264       super(testClass);
265     }
266 
267     @Nonnull
268     @Override
createSdkPicker()269     protected SdkPicker createSdkPicker() {
270       return new SdkPicker(asList(new SdkConfig(SdkConfig.MAX_SDK_VERSION)), null);
271     }
272 
273     @Override
getResourcesMode()274     ResourcesMode getResourcesMode() {
275       return ResourcesMode.legacy;
276     }
277   }
278 }
279