OLD | NEW |
---|---|
1 | |
2 # JUnit 4 Migration | 1 # JUnit 4 Migration |
3 | 2 |
4 As of Android 24 (N), JUnit3 style javatests have been deprecated for the new | 3 As of Android 24 (N), JUnit3 style javatests have been deprecated for the new |
5 JUnit4-based [Android Testing Support Library][1]. | 4 JUnit4-based [Android Testing Support Library][1]. |
6 We are in the process of changing all instrumentation tests in chromium to | 5 We are in the process of changing all instrumentation tests in chromium to |
7 JUnit4 style. This doc explains the differences between JUnit3 and JUnit4 | 6 JUnit4 style. This doc explains the differences between JUnit3 and JUnit4 |
8 instrumentation tests and how to write or convert them. | 7 instrumentation tests and how to write or convert them. |
9 | 8 |
9 [TOC] | |
10 | |
10 ## Differences between JUnit3 and JUnit4 instrumentation tests | 11 ## Differences between JUnit3 and JUnit4 instrumentation tests |
11 | 12 |
12 | | JUnit3 | JUnit4 | | 13 | | JUnit3 | JUnit4 | |
13 |--------------|-----------------------------------------------------|---------- --------------------------------| | 14 |--------------|-----------------------------------------------------|---------- --------------------------------| |
14 | Inheritance | Tests extends TestCase or child classes | No inheri tance. | | 15 | Inheritance | Tests extends TestCase or child classes | No inheri tance. | |
15 | Test methods | methods named with test prefix | methods a nnotated with @Test | | 16 | Test methods | methods named with test prefix | methods a nnotated with @Test | |
16 | Set up | setUp() method | public me thod annotated with @Before | | 17 | Set up | setUp() method | public me thod annotated with @Before | |
17 | Tear down | tearDown() method | public me thod annotated with @After | | 18 | Tear down | tearDown() method | public me thod annotated with @After | |
18 | Test runner | declared within test apk AndroidManifest.xml | Must spec ify `chromium-junit4:"true"` | | 19 | Test runner | declared within test apk AndroidManifest.xml | Must spec ify `chromium-junit4:"true"` | |
19 | Class runner | N/A | @RunWith( XClassRunner.class) | | 20 | Class runner | N/A | @RunWith( XClassRunner.class) | |
20 | Assertion | Extends from junit.framework.Assert, inherited APIs | Use stati c methods from org.junit.Assert | | 21 | Assertion | Extends from junit.framework.Assert, inherited APIs | Use stati c methods from org.junit.Assert | |
21 | 22 |
22 > Please note that during the migration, we support running JUnit3 and JUnit4 | 23 > Please note that during the migration, we support running JUnit3 and JUnit4 |
23 > tests in the same apk. This requires two tags, one each for JUnit3 and JUnit4. | 24 > tests in the same apk. This requires two tags, one each for JUnit3 and JUnit4. |
24 > The tag for the JUnit4 runner must specify `chromium-junit4:"true"` | 25 > The tag for the JUnit4 runner must specify `chromium-junit4:"true"` |
25 > ([Example][2]) | 26 > ([Example][2]) |
26 | 27 |
27 - **Other JUnit4 features**: | 28 - **Other JUnit4 features**: |
28 - Tests can be annotated to expect an exception, e.g. | 29 - Tests can be annotated to expect an exception, e.g. |
29 `@Test(expected=MyException.class)`. Tests annotated this way will | 30 `@Test(expected=MyException.class)`. Tests annotated this way will |
30 fail if they do not throw the given exception. | 31 fail if they do not throw the given exception. |
31 - **Test suite set up**: public static method annotated with `@BeforeClass` | 32 - **Test suite set up**: public static method annotated with `@BeforeClass` |
32 - **Test suite tear down**: public static method annotated with | 33 - **Test suite tear down**: public static method annotated with |
33 `@AfterClass` | 34 `@AfterClass` |
34 - **Replacement for JUnit3 test base classes** | 35 - **Replacement for JUnit3 test base classes** |
35 - [`TestRule`][3]: | 36 - [`TestRule`][3]: |
36 - TestRule is a class to **outsource your test setUp, tearDown, and | 37 - TestRule is a class to **outsource your test setUp, tearDown, and |
37 utility methods**. Since there are no more interitance and TestBase cl asses, | 38 utility methods**. Since there are no more interitance and TestBase cl asses, |
38 one should use TestRule for any API calls provided by its test base cl asses | 39 one should use TestRule for any API calls provided by its test base cl asses |
39 previously. | 40 previously. |
40 - One test can declare multiple TestRules and the class runner will run all of | 41 - One test can declare multiple TestRules and the class runner will run all of |
41 them. If the order of the TestRule matters to you, use | 42 them. If the order of the TestRule matters to you, use |
42 [`RuleChain`][8] | 43 [`RuleChain`][8] |
43 | 44 |
44 - [`ActivityTestRule`][4] | 45 - [`ActivityTestRule`][4] |
45 - `ActivityTestRule` is a special `TestRule` provided by Android Testing | 46 - `ActivityTestRule` is a special `TestRule` provided by Android Testing |
46 Support Library that allows tests to launch an Activity. | 47 Support Library that allows tests to launch an Activity. |
47 ([Documentation][4]) | 48 ([Documentation][4]) |
48 | 49 |
49 | |
50 ## Example Code of JUnit3 test and JUnit4 test | 50 ## Example Code of JUnit3 test and JUnit4 test |
51 | 51 |
52 JUnit3: | 52 JUnit3: |
53 | 53 |
54 ```java | 54 ```java |
55 public class MyTestClass extends MyActivityInstrumentationTestCase2<TestActi vity> { | 55 public class MyTestClass extends MyActivityInstrumentationTestCase2<TestActivity > { |
56 @Override | 56 @Override |
57 protected void setUp(){ | 57 protected void setUp(){ |
58 super.setUp(); | 58 super.setUp(); |
59 setActivityIntent(new Intent()); | 59 setActivityIntent(new Intent()); |
60 getActivity(); | 60 getActivity(); |
61 } | 61 } |
62 | 62 |
63 @Override | 63 @Override |
64 protected void tearDown() { | 64 protected void tearDown() { |
65 specialActionFromSuper(); | 65 specialActionFromSuper(); |
66 super.tearDown(); | 66 super.tearDown(); |
67 } | 67 } |
68 | 68 |
69 public void testA() { | 69 public void testA() { |
70 assertEquals(1, 1); | 70 assertEquals(1, 1); |
71 } | |
72 } | 71 } |
72 } | |
73 ``` | 73 ``` |
74 | 74 |
75 JUnit4: | 75 JUnit4: |
76 | 76 |
77 ```java | 77 ```java |
78 @RunWith(BaseJUnit4ClassRunner.class); | 78 @RunWith(BaseJUnit4ClassRunner.class); |
79 public class TestClass { | 79 public class TestClass { |
80 @Rule public ActivityTestRule<TestActivity> mRule = new ActivityTestRule <>(TestActivity.class); | 80 @Rule public ActivityTestRule<TestActivity> mRule = new ActivityTestRule<>(T estActivity.class); |
81 | 81 |
82 @Before | 82 @Before |
83 public void setUp() { //Must be public | 83 public void setUp() { //Must be public |
84 mRule.launchActivity(new Intent()); | 84 mRule.launchActivity(new Intent()); |
85 } | 85 } |
86 | 86 |
87 @After | 87 @After |
88 public void tearDown() { //Must be public | 88 public void tearDown() { //Must be public |
89 mRule.specialActionFromActivityTestRule(); | 89 mRule.specialActionFromActivityTestRule(); |
90 } | 90 } |
91 | 91 |
92 @Test | 92 @Test |
93 public void testA() { | 93 public void testA() { |
94 Assert.assertEquals(1, 1); | 94 Assert.assertEquals(1, 1); |
95 } | |
96 } | 95 } |
96 } | |
97 ``` | 97 ``` |
98 | 98 |
99 ## Migration process | 99 ## Migration process |
100 | 100 |
101 1. Add required libraries to your target dependencies in BUILD.gn | 101 1. Add required libraries to your target dependencies in BUILD.gn |
102 - JUnit 4 library: `//third_party/junit` | 102 - JUnit 4 library: `//third_party/junit` |
103 - Android Testing Support Rules: | 103 - Android Testing Support Rules: |
104 - `//third_party/android_support_test_runner:runner_java` (for `AndroidJU nitRunner`, etc) | 104 - `//third_party/android_support_test_runner:runner_java` |
105 - `//third_party/android_support_test_runner:rules_java` (for `ActivityTe stRule`, etc) | 105 (for `AndroidJUnitRunner`, etc) |
106 2. Add class runner to your test apk manifest. | 106 - `//third_party/android_support_test_runner:rules_java` |
107 ([example][2]) | 107 (for `ActivityTestRule`, etc) |
108 - Keep in mind you can have multiple instrumentations in your manifest. Our | 108 2. Add class runner to your test apk manifest. |
109 test runner will run JUnit4 tests with JUnit4 runner and JUnit3 tests | 109 ([example][2]) |
110 with non-JUnit4 runner. | 110 - Keep in mind you can have multiple instrumentations in your manifest. |
111 3. Refactor TestBase class to a TestRule class. | 111 Our test runner will run JUnit4 tests with JUnit4 runner and JUnit3 |
112 ([example CL](https://codereview.chromium.org/2632043002)) | 112 tests with non-JUnit4 runner. |
113 - +yolandyan will do this part, however, if you did refactoring yourself, | 113 3. Refactor TestBase class to a TestRule class. |
114 please add him as a reviewer for your CL and enjoy his eternal appreciatio n! | 114 ([example CL](https://codereview.chromium.org/2632043002)) |
115 4. Use [auto migrate script][5] | 115 - +yolandyan will do this part, however, if you did refactoring yourself, |
116 to or manually convert all JUnit3 tests to JUnit4 style in a your javatest | 116 please add him as a reviewer for your CL and enjoy his eternal appreciat ion! |
117 directory | 117 4. Use [auto migrate script][5] to or manually convert all JUnit3 tests to |
118 - we understand it's tedious to just manually write all the annotations, | 118 JUnit4 style in a your javatest directory |
119 change modifiers, etc to convert all the javatest, so we created an auto | 119 - we understand it's tedious to just manually write all the annotations, |
120 change script that helps you to convert all the javatests in a certain | 120 change modifiers, etc to convert all the javatest, so we created an auto |
121 directory. Please check its [README page][5] | 121 change script that helps you to convert all the javatests in a certain |
122 on instructions. | 122 directory. Please check its [README page][5] |
123 on instructions. | |
124 | |
125 | |
126 ## Customized TestRule example | |
127 | |
128 TestRule: | |
129 | |
130 ```java | |
131 public class MyRule implements TestRule { | |
132 // 1: Add utility methods... | |
133 | |
134 @Override | |
135 public Statement apply(final Statement base, Description desc) { | |
136 return new Statement() { | |
137 @Override | |
138 public void evaluate() { | |
139 // 2: Code here runs before @Before method | |
140 base.evaluate() | |
141 // 3: Code here runs after @After method | |
142 } | |
143 } | |
144 } | |
145 } | |
146 ``` | |
147 | |
123 | 148 |
124 ## Caveats | 149 ## Caveats |
125 | 150 |
126 1. Instrumentation tests that rely on test thread to have message handler | 151 1. Instrumentation tests that rely on test thread to have message handler |
127 will not work. For example error message: | 152 will not work. For example error message: |
128 ``` | |
129 java.lang.RuntimeException: Can't create handler inside thread that has not call ed Looper.prepare() | |
130 ``` | |
131 Please utilize `@UiThreadTest` or `ActivityTestRule.runOnUiThread(Runnable r) ` | |
132 to refactor these tests. For more, check this [github issue][6] | |
133 | 153 |
134 2. `assertEquals(float a, float b)` and `assertEquals(double a, double b)` are | 154 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() |
155 | |
156 Please utilize `@UiThreadTest` or | |
157 `ActivityTestRule.runOnUiThread(Runnable r)` to refactor these tests. | |
158 For more, check this [github issue][6] | |
nyquist
2017/03/23 21:28:00
Nit: GitHub
the real yoland
2017/03/24 01:35:49
Done
| |
159 | |
160 2. Use `@UiThreadTest` with caution. Currently, | |
nyquist
2017/03/23 21:28:00
Nit: 1. throughout.
the real yoland
2017/03/24 01:35:49
Done
| |
161 **@UiThreadTest is only effective when UiThreadTestRule or | |
162 ActivityTestRule is declared** in the test class. Please use | |
163 `android.support.test.annotation.UiThreadTest`, not | |
164 `android.test.UiThreadTest`. When using @UiThreadTest, **it would cause | |
165 `setUp` and `tearDown` to run in Ui Thread** as well. Avoid that by simply | |
166 calling [`runOnUiThread`][9] or [`runOnMainSync`][10] with a Runnable. | |
167 | |
168 ```java | |
169 //Wrong test | |
nyquist
2017/03/23 21:28:00
Nit: space after // and period at the end. Same be
the real yoland
2017/03/24 01:35:49
Done
| |
170 public class Test { | |
171 @Rule | |
172 public ActivityTestRule<MyActivity> mRule = new ActivityTestRule<>( | |
173 MyActivity.class> | |
174 | |
175 @Before | |
176 public void setUp() { | |
177 // Cause failure because this also runs on Ui Thread, while it | |
178 // is intended for Instrumentation worker thread | |
179 mRule.launchActivity() | |
180 } | |
181 | |
182 @UiThreadTest | |
183 public void test() { | |
184 actionThatNeedsUiThread(); | |
185 } | |
186 } | |
187 ``` | |
188 | |
189 The correct thing to do is | |
190 | |
191 ```java | |
192 //Correct test | |
193 public class Test { | |
194 @Rule | |
195 public ActivityTestRule<MyActivity> mRule = new ActivityTestRule<>( | |
196 MyActivity.class> | |
197 | |
198 @Before | |
199 public void setUp() { | |
200 mRule.launchActivity() | |
201 } | |
202 | |
203 public void test() { | |
204 mRule.runOnUiThread(new Runnable() { | |
205 @Override | |
206 public void run() { | |
207 actionThatNeedsUiThread(); | |
208 } | |
209 }); | |
210 } | |
211 } | |
212 ``` | |
213 | |
214 | |
215 3. `assertEquals(float a, float b)` and `assertEquals(double a, double b)` are | |
135 deprecated in JUnit4's Assert class. **Despite only generating a warning at | 216 deprecated in JUnit4's Assert class. **Despite only generating a warning at |
136 build time, they fail at runtime.** Please use | 217 build time, they fail at runtime.** Please use |
137 `Assert.assertEquals(float a, float b, float delta)` | 218 `Assert.assertEquals(float a, float b, float delta)` |
138 | 219 |
220 | |
139 ## Common questions | 221 ## Common questions |
140 | 222 |
141 - Q: are `@Test` and `@LargeTest/@MediumTest/@SmallTest` annotation both | 223 - Q: are `@Test` and `@LargeTest/@MediumTest/@SmallTest` annotation both |
nyquist
2017/03/23 21:28:00
Nit: "Are"
the real yoland
2017/03/24 01:35:49
Done
| |
142 necessary? | 224 necessary? |
143 - A: Yes, both are required for now. We plan to refactor this in the future. | 225 - A: Yes, both are required for now. We plan to refactor this in the |
144 - Q: Isn't the inheritance of the Test classes just migrated to inheritance | 226 future. |
145 of TestRules? | 227 - Q: Isn't the inheritance of the Test classes just migrated to inheritance |
146 - A: Yes. During the migration, we plan to maintain a 1:1 mapping between | 228 of TestRules? |
147 the test base classes and TestRules (e.g. ContentShellTestBase to | 229 - A: Yes. During the migration, we plan to maintain a 1:1 mapping between |
148 ContentShellTestRule in this [CL](https://codereview.chromium.org/2632043002 )). | 230 the test base classes and TestRules (e.g. ContentShellTestBase to |
149 This allows the auto convert script to replace API calls in any | 231 ContentShellTestRule in this |
150 JUnit3 tests. After the migration, we plan to refactor the TestRules to | 232 [CL](https://codereview.chromium.org/2632043002)). |
151 be more modular. | 233 This allows the auto convert script to replace API calls in any |
234 JUnit3 tests. After the migration, we plan to refactor the TestRules to | |
235 be more modular. | |
152 | 236 |
153 If you have any other questions, feel free to report in | 237 If you have any other questions, feel free to report in [this bug][7]. |
154 [this bug][7]. | |
155 | 238 |
156 ## Links and Crbugs | 239 ## Links and Crbugs |
157 | 240 |
158 - [Android Test Support Library documentation][1] | 241 - [Android Test Support Library documentation][1] |
159 - [Auto change script][5] | 242 - [Auto change script][5] |
160 - [Crbug for JUnit3 to JUnit4 migration][7] | 243 - [Crbug for JUnit3 to JUnit4 migration][7] |
161 | 244 |
162 [1]: https://developer.android.com/topic/libraries/testing-support-library/index .html | 245 [1]: https://developer.android.com/topic/libraries/testing-support-library/index .html |
163 [2]: https://cs.chromium.org/chromium/src/android_webview/tools/system_webview_s hell/layout_tests/AndroidManifest.xml?l=36 | 246 [2]: https://cs.chromium.org/chromium/src/android_webview/tools/system_webview_s hell/layout_tests/AndroidManifest.xml?l=36 |
164 [3]: http://junit.org/junit4/javadoc/4.12/org/junit/rules/TestRule.html | 247 [3]: http://junit.org/junit4/javadoc/4.12/org/junit/rules/TestRule.html |
165 [4]: https://developer.android.com/reference/android/support/test/rule/ActivityT estRule.html | 248 [4]: https://developer.android.com/reference/android/support/test/rule/ActivityT estRule.html |
166 [5]: https://github.com/yoland68/chromium-junit-auto-migrate | 249 [5]: https://github.com/yoland68/chromium-junit-auto-migrate |
167 [6]: http://github.com/skyisle/android-test-kit/issues/121 | 250 [6]: http://github.com/skyisle/android-test-kit/issues/121 |
168 [7]: https://bugs.chromium.org/p/chromium/issues/detail?id=640116 | 251 [7]: https://bugs.chromium.org/p/chromium/issues/detail?id=640116 |
169 [8]: http://junit.org/junit4/javadoc/4.12/org/junit/rules/RuleChain.html | 252 [8]: http://junit.org/junit4/javadoc/4.12/org/junit/rules/RuleChain.html |
253 [9]: https://developer.android.com/reference/android/app/Instrumentation.html#ru nOnMainSync(java.lang.Runnable) | |
254 [10]: https://developer.android.com/reference/android/support/test/rule/UiThread TestRule.html#runOnUiThread(java.lang.Runnable) | |
OLD | NEW |