Chromium Code Reviews| Index: testing/android/docs/junit4.md |
| diff --git a/testing/android/docs/junit4.md b/testing/android/docs/junit4.md |
| index d697bcd5e7ffc0073264f9cf8b0cc5fb2436fae4..1168ff5f2e9d1f52746af2ce506630f1f97a3a65 100644 |
| --- a/testing/android/docs/junit4.md |
| +++ b/testing/android/docs/junit4.md |
| @@ -1,4 +1,3 @@ |
| - |
| # JUnit 4 Migration |
| As of Android 24 (N), JUnit3 style javatests have been deprecated for the new |
| @@ -7,6 +6,8 @@ We are in the process of changing all instrumentation tests in chromium to |
| JUnit4 style. This doc explains the differences between JUnit3 and JUnit4 |
| instrumentation tests and how to write or convert them. |
| +[TOC] |
| + |
| ## Differences between JUnit3 and JUnit4 instrumentation tests |
| | | JUnit3 | JUnit4 | |
| @@ -24,14 +25,14 @@ instrumentation tests and how to write or convert them. |
| > The tag for the JUnit4 runner must specify `chromium-junit4:"true"` |
| > ([Example][2]) |
| -- **Other JUnit4 features**: |
| +- **Other JUnit4 features**: |
| - Tests can be annotated to expect an exception, e.g. |
| `@Test(expected=MyException.class)`. Tests annotated this way will |
| fail if they do not throw the given exception. |
| - **Test suite set up**: public static method annotated with `@BeforeClass` |
| - **Test suite tear down**: public static method annotated with |
| `@AfterClass` |
| -- **Replacement for JUnit3 test base classes** |
| +- **Replacement for JUnit3 test base classes** |
| - [`TestRule`][3]: |
| - TestRule is a class to **outsource your test setUp, tearDown, and |
| utility methods**. Since there are no more interitance and TestBase classes, |
| @@ -46,112 +47,194 @@ instrumentation tests and how to write or convert them. |
| Support Library that allows tests to launch an Activity. |
| ([Documentation][4]) |
| - |
| ## Example Code of JUnit3 test and JUnit4 test |
| JUnit3: |
| ```java |
| - public class MyTestClass extends MyActivityInstrumentationTestCase2<TestActivity> { |
| - @Override |
| - protected void setUp(){ |
| - super.setUp(); |
| - setActivityIntent(new Intent()); |
| - getActivity(); |
| - } |
| +public class MyTestClass extends MyActivityInstrumentationTestCase2<TestActivity> { |
| + @Override |
| + protected void setUp(){ |
| + super.setUp(); |
| + setActivityIntent(new Intent()); |
| + getActivity(); |
| + } |
| - @Override |
| - protected void tearDown() { |
| - specialActionFromSuper(); |
| - super.tearDown(); |
| - } |
| + @Override |
| + protected void tearDown() { |
| + specialActionFromSuper(); |
| + super.tearDown(); |
| + } |
| - public void testA() { |
| - assertEquals(1, 1); |
| - } |
| + public void testA() { |
| + assertEquals(1, 1); |
| } |
| +} |
| ``` |
| JUnit4: |
| ```java |
| - @RunWith(BaseJUnit4ClassRunner.class); |
| - public class TestClass { |
| - @Rule public ActivityTestRule<TestActivity> mRule = new ActivityTestRule<>(TestActivity.class); |
| +@RunWith(BaseJUnit4ClassRunner.class); |
| +public class TestClass { |
| + @Rule public ActivityTestRule<TestActivity> mRule = new ActivityTestRule<>(TestActivity.class); |
| - @Before |
| - public void setUp() { //Must be public |
| - mRule.launchActivity(new Intent()); |
| - } |
| + @Before |
| + public void setUp() { //Must be public |
| + mRule.launchActivity(new Intent()); |
| + } |
| - @After |
| - public void tearDown() { //Must be public |
| - mRule.specialActionFromActivityTestRule(); |
| - } |
| + @After |
| + public void tearDown() { //Must be public |
| + mRule.specialActionFromActivityTestRule(); |
| + } |
| - @Test |
| - public void testA() { |
| - Assert.assertEquals(1, 1); |
| - } |
| + @Test |
| + public void testA() { |
| + Assert.assertEquals(1, 1); |
| } |
| +} |
| ``` |
| ## Migration process |
| -1. Add required libraries to your target dependencies in BUILD.gn |
| - - JUnit 4 library: `//third_party/junit` |
| - - Android Testing Support Rules: |
| - - `//third_party/android_support_test_runner:runner_java` (for `AndroidJUnitRunner`, etc) |
| - - `//third_party/android_support_test_runner:rules_java` (for `ActivityTestRule`, etc) |
| -2. Add class runner to your test apk manifest. |
| - ([example][2]) |
| - - Keep in mind you can have multiple instrumentations in your manifest. Our |
| - test runner will run JUnit4 tests with JUnit4 runner and JUnit3 tests |
| - with non-JUnit4 runner. |
| -3. Refactor TestBase class to a TestRule class. |
| - ([example CL](https://codereview.chromium.org/2632043002)) |
| - - +yolandyan will do this part, however, if you did refactoring yourself, |
| - please add him as a reviewer for your CL and enjoy his eternal appreciation! |
| -4. Use [auto migrate script][5] |
| - to or manually convert all JUnit3 tests to JUnit4 style in a your javatest |
| - directory |
| - - we understand it's tedious to just manually write all the annotations, |
| - change modifiers, etc to convert all the javatest, so we created an auto |
| - change script that helps you to convert all the javatests in a certain |
| - directory. Please check its [README page][5] |
| - on instructions. |
| +1. Add required libraries to your target dependencies in BUILD.gn |
| + - JUnit 4 library: `//third_party/junit` |
| + - Android Testing Support Rules: |
| + - `//third_party/android_support_test_runner:runner_java` |
| + (for `AndroidJUnitRunner`, etc) |
| + - `//third_party/android_support_test_runner:rules_java` |
| + (for `ActivityTestRule`, etc) |
| +2. Add class runner to your test apk manifest. |
| + ([example][2]) |
| + - Keep in mind you can have multiple instrumentations in your manifest. |
| + Our test runner will run JUnit4 tests with JUnit4 runner and JUnit3 |
| + tests with non-JUnit4 runner. |
| +3. Refactor TestBase class to a TestRule class. |
| + ([example CL](https://codereview.chromium.org/2632043002)) |
| + - +yolandyan will do this part, however, if you did refactoring yourself, |
| + please add him as a reviewer for your CL and enjoy his eternal appreciation! |
| +4. Use [auto migrate script][5] to or manually convert all JUnit3 tests to |
| + JUnit4 style in a your javatest directory |
| + - we understand it's tedious to just manually write all the annotations, |
| + change modifiers, etc to convert all the javatest, so we created an auto |
| + change script that helps you to convert all the javatests in a certain |
| + directory. Please check its [README page][5] |
| + on instructions. |
| + |
| + |
| +## Customized TestRule example |
| + |
| +TestRule: |
| + |
| +```java |
| +public class MyRule implements TestRule { |
| + // 1: Add utility methods... |
| + |
| + @Override |
| + public Statement apply(final Statement base, Description desc) { |
| + return new Statement() { |
| + @Override |
| + public void evaluate() { |
| + // 2: Code here runs before @Before method |
| + base.evaluate() |
| + // 3: Code here runs after @After method |
| + } |
| + } |
| + } |
| +} |
| +``` |
| + |
| ## Caveats |
| -1. Instrumentation tests that rely on test thread to have message handler |
| - will not work. For example error message: |
| -``` |
| -java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() |
| -``` |
| - Please utilize `@UiThreadTest` or `ActivityTestRule.runOnUiThread(Runnable r)` |
| - to refactor these tests. For more, check this [github issue][6] |
| +1. Instrumentation tests that rely on test thread to have message handler |
| + will not work. For example error message: |
| + |
| + java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() |
| + |
| + Please utilize `@UiThreadTest` or |
| + `ActivityTestRule.runOnUiThread(Runnable r)` to refactor these tests. |
| + 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
|
| + |
| +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
|
| + **@UiThreadTest is only effective when UiThreadTestRule or |
| + ActivityTestRule is declared** in the test class. Please use |
| + `android.support.test.annotation.UiThreadTest`, not |
| + `android.test.UiThreadTest`. When using @UiThreadTest, **it would cause |
| + `setUp` and `tearDown` to run in Ui Thread** as well. Avoid that by simply |
| + calling [`runOnUiThread`][9] or [`runOnMainSync`][10] with a Runnable. |
| + |
| + ```java |
| + //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
|
| + public class Test { |
| + @Rule |
| + public ActivityTestRule<MyActivity> mRule = new ActivityTestRule<>( |
| + MyActivity.class> |
| + |
| + @Before |
| + public void setUp() { |
| + // Cause failure because this also runs on Ui Thread, while it |
| + // is intended for Instrumentation worker thread |
| + mRule.launchActivity() |
| + } |
| + |
| + @UiThreadTest |
| + public void test() { |
| + actionThatNeedsUiThread(); |
| + } |
| + } |
| + ``` |
| + |
| + The correct thing to do is |
| -2. `assertEquals(float a, float b)` and `assertEquals(double a, double b)` are |
| + ```java |
| + //Correct test |
| + public class Test { |
| + @Rule |
| + public ActivityTestRule<MyActivity> mRule = new ActivityTestRule<>( |
| + MyActivity.class> |
| + |
| + @Before |
| + public void setUp() { |
| + mRule.launchActivity() |
| + } |
| + |
| + public void test() { |
| + mRule.runOnUiThread(new Runnable() { |
| + @Override |
| + public void run() { |
| + actionThatNeedsUiThread(); |
| + } |
| + }); |
| + } |
| + } |
| + ``` |
| + |
| + |
| +3. `assertEquals(float a, float b)` and `assertEquals(double a, double b)` are |
| deprecated in JUnit4's Assert class. **Despite only generating a warning at |
| build time, they fail at runtime.** Please use |
| `Assert.assertEquals(float a, float b, float delta)` |
| + |
| ## Common questions |
| -- Q: are `@Test` and `@LargeTest/@MediumTest/@SmallTest` annotation both |
| - necessary? |
| - - A: Yes, both are required for now. We plan to refactor this in the future. |
| -- Q: Isn't the inheritance of the Test classes just migrated to inheritance |
| - of TestRules? |
| - - A: Yes. During the migration, we plan to maintain a 1:1 mapping between |
| - the test base classes and TestRules (e.g. ContentShellTestBase to |
| - ContentShellTestRule in this [CL](https://codereview.chromium.org/2632043002)). |
| - This allows the auto convert script to replace API calls in any |
| - JUnit3 tests. After the migration, we plan to refactor the TestRules to |
| - be more modular. |
| - |
| -If you have any other questions, feel free to report in |
| -[this bug][7]. |
| +- 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
|
| + necessary? |
| + - A: Yes, both are required for now. We plan to refactor this in the |
| + future. |
| +- Q: Isn't the inheritance of the Test classes just migrated to inheritance |
| + of TestRules? |
| + - A: Yes. During the migration, we plan to maintain a 1:1 mapping between |
| + the test base classes and TestRules (e.g. ContentShellTestBase to |
| + ContentShellTestRule in this |
| + [CL](https://codereview.chromium.org/2632043002)). |
| + This allows the auto convert script to replace API calls in any |
| + JUnit3 tests. After the migration, we plan to refactor the TestRules to |
| + be more modular. |
| + |
| +If you have any other questions, feel free to report in [this bug][7]. |
| ## Links and Crbugs |
| @@ -167,3 +250,5 @@ If you have any other questions, feel free to report in |
| [6]: http://github.com/skyisle/android-test-kit/issues/121 |
| [7]: https://bugs.chromium.org/p/chromium/issues/detail?id=640116 |
| [8]: http://junit.org/junit4/javadoc/4.12/org/junit/rules/RuleChain.html |
| +[9]: https://developer.android.com/reference/android/app/Instrumentation.html#runOnMainSync(java.lang.Runnable) |
| +[10]: https://developer.android.com/reference/android/support/test/rule/UiThreadTestRule.html#runOnUiThread(java.lang.Runnable) |