Chromium Code Reviews| 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 |