mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 1 | # JUnit Tests |
| 2 | |
| 3 | JUnit tests are Java unit tests. These tests run locally on your workstation. |
| 4 | |
| 5 | [TOC] |
| 6 | |
| 7 | ## Writing a JUnit test |
| 8 | |
| 9 | When writing JUnit tests, you must decide whether you need to use Android code. |
| 10 | If you want to use Android code you must write a [Robolectric](http://robolectric.org/) test. |
| 11 | |
| 12 | ### JUnit tests (without Android) |
| 13 | |
Mohamed Heikal | 2c5f2fb | 2022-06-30 18:07:25 | [diff] [blame] | 14 | Build these types of test using the `robolectric_binary` GN template. |
mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 15 | |
| 16 | If you don't need to use any Android code in your tests, you can write plain, |
| 17 | old JUnit tests. Some more documentation about writing JUnit tests can be |
| 18 | found [here](https://github.com/junit-team/junit4/wiki/Getting-started). |
| 19 | |
| 20 | #### Example Code |
| 21 | |
| 22 | ```java |
| 23 | package org.chromium.sample.test; |
| 24 | |
| 25 | import static org.junit.Assert.assertTrue; |
| 26 | |
| 27 | import org.junit.Test; |
| 28 | import org.junit.runner.RunWith; |
| 29 | import org.junit.runners.BlockJUnit4ClassRunner; |
| 30 | |
| 31 | @RunWith(BlockJUnit4ClassRunner.class) |
| 32 | public class MyJUnitTest { |
| 33 | |
| 34 | @Test |
| 35 | public void exampleTest() { |
| 36 | boolean shouldWriteMoreJUnitTests = true; |
| 37 | assertTrue(shouldWriteMoreJUnitTests); |
| 38 | } |
| 39 | } |
| 40 | ``` |
| 41 | |
| 42 | #### Example within Chromium |
| 43 | |
| 44 | See the [junit_unit_tests](https://cs.chromium.org/chromium/src/testing/android/junit/BUILD.gn) test suite. |
| 45 | |
| 46 | ### JUnit tests with Robolectric |
| 47 | |
Mohamed Heikal | 2c5f2fb | 2022-06-30 18:07:25 | [diff] [blame] | 48 | Build these types of test using the `robolectric_binary` GN template. |
mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 49 | |
| 50 | Robolectric is a unit testing framework that lets you run tests with Android |
| 51 | code on your workstation. It does this by providing a special version of the |
| 52 | Android SDK jar that can run in your host JVM. Some more information about |
| 53 | Robolectric can be found [here](http://robolectric.org/). |
| 54 | |
mikecase | 5e865032 | 2017-05-16 18:05:16 | [diff] [blame] | 55 | One on the main benefits of using Robolectric framework are [shadow classes](http://robolectric.org/extending/). |
| 56 | Robolectric comes with many prebuilt shadow classes and also lets you define |
| 57 | your own. Whenever an object is instantiated within a Robolectric test, |
| 58 | Robolectric looks for a corresponding shadow class (marked by |
| 59 | `@Implements(ClassBeingShadowed.class)`). If found, any time a method is invoked |
| 60 | on the object, the shadow class's implementation of the method is invoked first. |
| 61 | This works even for static and final methods. |
| 62 | |
mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 63 | #### Useful Tips |
| 64 | |
Ben Joyce | eac22e8 | 2022-03-23 06:30:06 | [diff] [blame] | 65 | * Use `@RunWith(BaseRobolectricTestRunner.class)` for all Chromium Robolectric tests. |
mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 66 | * You can specify the Android SDK to run your test with with `@Config(sdk = ??)`. |
| 67 | |
| 68 | > Currently, only SDK levels 18, 21, and 25 are supported in Chromium |
| 69 | > but more can be added on request. |
| 70 | |
| 71 | #### Example Code |
| 72 | |
| 73 | ```java |
| 74 | package org.chromium.sample.test; |
| 75 | |
| 76 | import static org.junit.Assert.assertTrue; |
| 77 | |
| 78 | import android.text.TextUtils; |
| 79 | |
| 80 | import org.junit.Test; |
| 81 | import org.junit.runner.RunWith; |
| 82 | import org.robolectric.annotation.Config; |
| 83 | |
Ben Joyce | eac22e8 | 2022-03-23 06:30:06 | [diff] [blame] | 84 | import org.chromium.base.test.BaseRobolectricTestRunner; |
mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 85 | |
Ben Joyce | eac22e8 | 2022-03-23 06:30:06 | [diff] [blame] | 86 | // Be sure to specify to run tests with a RobolectricTestRunner. The |
mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 87 | // default JUnit test runner won't load the Robolectric Android code properly. |
Ben Joyce | eac22e8 | 2022-03-23 06:30:06 | [diff] [blame] | 88 | // BaseRobolectricTestRunner will do some common initializations. If this is |
Henrique Nakashima | 485c8acf | 2023-04-21 20:38:25 | [diff] [blame] | 89 | // not desired, then RobolectricTestRunner could be used directly. |
Ben Joyce | eac22e8 | 2022-03-23 06:30:06 | [diff] [blame] | 90 | @RunWith(BaseRobolectricTestRunner.class) |
mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 91 | // Can specify some Robolectric related configs here. |
| 92 | // More about configuring Robolectric at http://robolectric.org/configuring/. |
| 93 | // SDK will default to the latest we support in Chromium. |
| 94 | @Config(manifest = Config.NONE, sdk = 21) |
| 95 | public class MyRobolectricJUnitTest { |
| 96 | |
| 97 | @Test |
| 98 | public void exampleTest() { |
| 99 | String testString = "test"; |
| 100 | |
| 101 | // Even though these tests runs on the host, Android classes are |
| 102 | // available to use thanks to Robolectric. |
| 103 | assertTrue(TextUtils.equals(testString, "test")); |
| 104 | } |
| 105 | } |
| 106 | ``` |
| 107 | |
Mohamed Heikal | 2c5f2fb | 2022-06-30 18:07:25 | [diff] [blame] | 108 | #### Example robolectric_binary build template. |
mikecase | 5e865032 | 2017-05-16 18:05:16 | [diff] [blame] | 109 | |
| 110 | ```python |
Mohamed Heikal | 2c5f2fb | 2022-06-30 18:07:25 | [diff] [blame] | 111 | robolectric_binary("my_robolectric_tests") { |
mikecase | 5e865032 | 2017-05-16 18:05:16 | [diff] [blame] | 112 | |
Natalie Chouinard | cbdc6dc | 2019-12-24 00:02:35 | [diff] [blame] | 113 | sources = [ |
mikecase | 5e865032 | 2017-05-16 18:05:16 | [diff] [blame] | 114 | "java/src/foo/bar/MyJUnitTest.java" |
Natalie Chouinard | cbdc6dc | 2019-12-24 00:02:35 | [diff] [blame] | 115 | ] |
mikecase | 5e865032 | 2017-05-16 18:05:16 | [diff] [blame] | 116 | |
| 117 | deps = [ |
| 118 | "//my/test:dependency", |
| 119 | ] |
| 120 | |
| 121 | # Sets app's package name in Robolectric tests. You need to specify |
| 122 | # this variable in order for Robolectric to be able to find your app's |
| 123 | # resources. |
| 124 | package_name = manifest_package |
| 125 | } |
| 126 | ``` |
| 127 | |
mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 128 | #### Example within Chromium |
| 129 | |
| 130 | See the [content_junit_tests](https://cs.chromium.org/chromium/src/content/public/android/BUILD.gn) test suite. |
| 131 | |
| 132 | ## Running JUnit tests |
| 133 | |
| 134 | After writing a test, you can run it by: |
| 135 | |
Mohamed Heikal | 2c5f2fb | 2022-06-30 18:07:25 | [diff] [blame] | 136 | 1. Adding the test file to a `robolectric_binary` GN target. |
mikecase | d05ab85 | 2017-03-15 17:10:17 | [diff] [blame] | 137 | 2. Rebuild. |
| 138 | 3. GN will generate binary `<out_dir>/bin/run_<suite name>` which |
| 139 | can be used to run your test. |
| 140 | |
| 141 | For example, the following can be used to run chrome_junit_tests. |
| 142 | |
| 143 | ```bash |
| 144 | # Build the test suite after adding our new test. |
| 145 | ninja -C out/Debug chrome_junit_tests |
| 146 | |
| 147 | # Run the test! |
| 148 | out/Debug/bin/run_chrome_junit_tests |
Ben Joyce | eac22e8 | 2022-03-23 06:30:06 | [diff] [blame] | 149 | ``` |