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 1. 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 1. 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 1. 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] |
| 159 |
| 160 1. Use `@UiThreadTest` with caution. Currently, |
| 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 |
| 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 1. `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 |
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 |