Skip to content

Commit 4d35f71

Browse files
authored
[All] Share tests to run on Robolectric & Emulators (#180)
* Add Robolectric test support on :insets * Add Robolectric test support to :flowlayout * Add Robolectric test support on :pager * Missed PagerStateTest * Remove test-parameter-injector As we can't use it with Robolectric * Migrate :swiperefresh tests to Robolectric * Migrate :appcompat-theme tests to Robolectric * Rename package in :internal-testutils * Migrate SystemUiController tests to Robolectric * Only run necessary tests on PRs/commits Most tests are covered by Robolectric, but we still need to run the remaining tests on device. Also setup a twice-daily run which runs all tests on devices, similar to what we currently run. Extract all of the logic into a shell script for easy re-use. * Stop using trap. Messes with CI * Migrate :placeholder to Robolectric * Move more common utils to internal-testutils * Revert permissions waitUntil * Reduce number of Pager instrumented tests * Add comments to tests * Revert CI gradle command
1 parent 66cb7a3 commit 4d35f71

File tree

69 files changed

+1115
-296
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1115
-296
lines changed

.github/workflows/build.yml

+32-10
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ jobs:
1818

1919
runs-on: ubuntu-latest
2020
timeout-minutes: 30
21-
env:
22-
TERM: dumb
2321

2422
steps:
2523
- uses: actions/checkout@v2
24+
with:
25+
# Fetch expanded history, which is needed for affected module detection
26+
fetch-depth: '500'
2627

2728
- name: Copy CI gradle.properties
2829
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
@@ -46,8 +47,29 @@ jobs:
4647
~/.gradle/caches/build-cache-*
4748
key: gradle-${{ hashFiles('checksum.txt') }}
4849

49-
- name: Build, lint and spotless
50-
run: ./gradlew spotlessCheck assemble assembleAndroidTest lintDebug metalavaCheckCompatibility --scan
50+
- name: Build
51+
run: |
52+
./gradlew --scan --stacktrace \
53+
spotlessCheck \
54+
assemble \
55+
metalavaCheckCompatibility \
56+
lintDebug
57+
58+
- name: Unit Tests
59+
run: |
60+
./scripts/run-tests.sh \
61+
--unit-tests \
62+
--run-affected \
63+
--affected-base-ref=$BASE_REF
64+
65+
- name: Upload test results
66+
if: always()
67+
uses: actions/upload-artifact@v2
68+
with:
69+
name: test-results-robolectric
70+
path: |
71+
**/build/test-results/*
72+
**/build/reports/*
5173
5274
- name: Clean secrets
5375
if: always()
@@ -56,7 +78,7 @@ jobs:
5678
test:
5779
runs-on: macos-11.0
5880
needs: build
59-
timeout-minutes: 70
81+
timeout-minutes: 50
6082

6183
strategy:
6284
# Allow tests to continue on other devices if they fail on one device.
@@ -71,8 +93,8 @@ jobs:
7193
steps:
7294
- uses: actions/checkout@v2
7395
with:
74-
# 0 == fetch all history, which is needed for affected module detection
75-
fetch-depth: '0'
96+
# Fetch expanded history, which is needed for affected module detection
97+
fetch-depth: '500'
7698

7799
- name: Copy CI gradle.properties
78100
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
@@ -116,7 +138,7 @@ jobs:
116138
target: ${{ steps.determine-target.outputs.TARGET }}
117139
profile: Galaxy Nexus
118140
# We run all affected tests of the PR (or commit)
119-
script: ./scripts/run-device-tests.sh --log-file=logcat.txt --run-affected --affected-base-ref=$BASE_REF --shard-index=${{ matrix.shard }} --shard-count=2
141+
script: ./scripts/run-tests.sh --log-file=logcat.txt --run-affected --affected-base-ref=$BASE_REF --shard-index=${{ matrix.shard }} --shard-count=2
120142

121143
- name: Clean secrets
122144
if: always()
@@ -142,7 +164,7 @@ jobs:
142164
if: github.event_name == 'push' # only deploy for pushed commits (not PRs)
143165

144166
runs-on: ubuntu-latest
145-
needs: [build, test]
167+
needs: [ build, test ]
146168
timeout-minutes: 30
147169
env:
148170
TERM: dumb
@@ -173,7 +195,7 @@ jobs:
173195
key: gradle-${{ hashFiles('checksum.txt') }}
174196

175197
- name: Deploy to Sonatype
176-
run: ./gradlew publish --no-parallel
198+
run: ./gradlew publish --no-parallel --stacktrace
177199
env:
178200
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }}
179201
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}

.github/workflows/device-tests.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ jobs:
6060
fi
6161
echo "::set-output name=TARGET::$TARGET"
6262
63-
- name: Run tests
63+
- name: Run device tests
6464
uses: reactivecircus/android-emulator-runner@v2
6565
with:
6666
api-level: ${{ matrix.api-level }}
6767
target: ${{ steps.determine-target.outputs.TARGET }}
6868
profile: Galaxy Nexus
6969
# We run all tests, sharding them over 3 shards
70-
script: ./scripts/run-device-tests.sh --log-file=logcat.txt --shard-index=${{ matrix.shard }} --shard-count=3
70+
script: ./scripts/run-tests.sh --log-file=logcat.txt --shard-index=${{ matrix.shard }} --shard-count=3
7171

7272
- name: Clean secrets
7373
if: always()

appcompat-theme/build.gradle

+25
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,17 @@ android {
6868
}
6969
animationsDisabled true
7070
}
71+
72+
sourceSets {
73+
test {
74+
java.srcDirs += 'src/sharedTest/kotlin'
75+
res.srcDirs += 'src/sharedTest/res'
76+
}
77+
androidTest {
78+
java.srcDirs += 'src/sharedTest/kotlin'
79+
res.srcDirs += 'src/sharedTest/res'
80+
}
81+
}
7182
}
7283

7384
dependencies {
@@ -76,9 +87,23 @@ dependencies {
7687

7788
api libs.androidx.appcompat
7889

90+
// ======================
91+
// Test dependencies
92+
// ======================
93+
94+
androidTestImplementation project(':internal-testutils')
95+
testImplementation project(':internal-testutils')
96+
7997
androidTestImplementation libs.junit
98+
testImplementation libs.junit
99+
80100
androidTestImplementation libs.compose.ui.test.junit4
101+
testImplementation libs.compose.ui.test.junit4
102+
81103
androidTestImplementation libs.androidx.test.runner
104+
testImplementation libs.androidx.test.runner
105+
106+
testImplementation libs.robolectric
82107
}
83108

84109
apply plugin: 'com.vanniktech.maven.publish'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2021 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.accompanist.appcompattheme
18+
19+
import androidx.appcompat.app.AppCompatActivity
20+
import androidx.compose.material.MaterialTheme
21+
import androidx.compose.ui.text.font.Font
22+
import androidx.compose.ui.text.font.FontWeight
23+
import androidx.compose.ui.text.font.toFontFamily
24+
import androidx.test.filters.SdkSuppress
25+
import com.google.accompanist.appcompattheme.test.R
26+
import org.junit.Test
27+
import org.junit.runner.RunWith
28+
import org.junit.runners.Parameterized
29+
30+
/**
31+
* Version of [BaseAppCompatThemeTest] which is designed to be run on device/emulators.
32+
*/
33+
@RunWith(Parameterized::class)
34+
class InstrumentedAppCompatThemeTest<T : AppCompatActivity>(
35+
activityClass: Class<T>
36+
) : BaseAppCompatThemeTest<T>(activityClass) {
37+
companion object {
38+
@JvmStatic
39+
@Parameterized.Parameters
40+
fun activities() = listOf(
41+
DarkAppCompatActivity::class.java,
42+
LightAppCompatActivity::class.java
43+
)
44+
}
45+
46+
/**
47+
* On API 21-22, the family is loaded with only the 400 font.
48+
*
49+
* This only works on device as Robolectric seems to always use the behavior from API 23+,
50+
* which is not what we want to test.
51+
*/
52+
@Test
53+
@SdkSuppress(maxSdkVersion = 22)
54+
fun type_rubik_family_api21() = composeTestRule.setContent {
55+
val rubik = Font(R.font.rubik, FontWeight.W400).toFontFamily()
56+
57+
WithThemeOverlay(R.style.ThemeOverlay_RubikFontFamily) {
58+
AppCompatTheme {
59+
MaterialTheme.typography.assertFontFamily(expected = rubik)
60+
}
61+
}
62+
}
63+
}

appcompat-theme/src/androidTest/java/com/google/accompanist/appcompattheme/AppCompatThemeTest.kt renamed to appcompat-theme/src/sharedTest/kotlin/com/google/accompanist/appcompattheme/BaseAppCompatThemeTest.kt

+10-29
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,20 @@ import androidx.compose.ui.text.font.Font
3333
import androidx.compose.ui.text.font.FontFamily
3434
import androidx.compose.ui.text.font.FontWeight
3535
import androidx.compose.ui.text.font.toFontFamily
36-
import androidx.test.filters.LargeTest
3736
import androidx.test.filters.SdkSuppress
3837
import com.google.accompanist.appcompattheme.test.R
3938
import org.junit.Assert.assertEquals
4039
import org.junit.Rule
4140
import org.junit.Test
42-
import org.junit.runner.RunWith
43-
import org.junit.runners.Parameterized
44-
45-
@LargeTest
46-
@RunWith(Parameterized::class)
47-
class AppCompatThemeTest<T : AppCompatActivity>(activityClass: Class<T>) {
48-
companion object {
49-
@JvmStatic
50-
@Parameterized.Parameters
51-
fun activities() = listOf(
52-
DarkAppCompatActivity::class.java,
53-
LightAppCompatActivity::class.java
54-
)
55-
}
5641

42+
/**
43+
* Class which contains the majority of the tests. This class is extended
44+
* in both the `androidTest` and `test` source sets for setup of the relevant
45+
* test runner.
46+
*/
47+
abstract class BaseAppCompatThemeTest<T : AppCompatActivity>(
48+
activityClass: Class<T>
49+
) {
5750
@get:Rule
5851
val composeTestRule = createAndroidComposeRule(activityClass)
5952

@@ -125,21 +118,9 @@ class AppCompatThemeTest<T : AppCompatActivity>(activityClass: Class<T>) {
125118
}
126119
}
127120

128-
@Test
129-
@SdkSuppress(maxSdkVersion = 22) // On API 21-22, the family is loaded with only the 400 font
130-
fun type_rubik_family_api21() = composeTestRule.setContent {
131-
val rubik = Font(R.font.rubik, FontWeight.W400).toFontFamily()
132-
133-
WithThemeOverlay(R.style.ThemeOverlay_RubikFontFamily) {
134-
AppCompatTheme {
135-
MaterialTheme.typography.assertFontFamily(expected = rubik)
136-
}
137-
}
138-
}
139-
140121
@Test
141122
@SdkSuppress(minSdkVersion = 23) // XML font families with >1 fonts are only supported on API 23+
142-
fun type_rubik_family_api23() = composeTestRule.setContent {
123+
open fun type_rubik_family_api23() = composeTestRule.setContent {
143124
val rubik = FontFamily(
144125
Font(R.font.rubik_300, FontWeight.W300),
145126
Font(R.font.rubik_400, FontWeight.W400),
@@ -165,7 +146,7 @@ class AppCompatThemeTest<T : AppCompatActivity>(activityClass: Class<T>) {
165146
}
166147
}
167148

168-
private fun Typography.assertFontFamily(expected: FontFamily) {
149+
internal fun Typography.assertFontFamily(expected: FontFamily) {
169150
assertEquals(expected, h1.fontFamily)
170151
assertEquals(expected, h2.fontFamily)
171152
assertEquals(expected, h3.fontFamily)

appcompat-theme/src/androidTest/java/com/google/accompanist/appcompattheme/NotAppCompatThemeTest.kt renamed to appcompat-theme/src/sharedTest/kotlin/com/google/accompanist/appcompattheme/NotAppCompatThemeTest.kt

+2-4
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@
1717
package com.google.accompanist.appcompattheme
1818

1919
import androidx.compose.ui.test.junit4.createAndroidComposeRule
20-
import androidx.test.filters.MediumTest
20+
import androidx.test.ext.junit.runners.AndroidJUnit4
2121
import org.junit.Rule
2222
import org.junit.Test
2323
import org.junit.runner.RunWith
24-
import org.junit.runners.JUnit4
2524

26-
@MediumTest
27-
@RunWith(JUnit4::class)
25+
@RunWith(AndroidJUnit4::class)
2826
class NotAppCompatThemeTest {
2927
@get:Rule
3028
val composeTestRule = createAndroidComposeRule<NotAppCompatActivity>()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!--
2+
~ Copyright 2020 The Android Open Source Project
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ https://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
-->
16+
17+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
18+
package="com.google.accompanist.appcompattheme">
19+
20+
<application>
21+
<activity
22+
android:name=".LightAppCompatActivity"
23+
android:theme="@style/Theme.AppCompatThemeTest" />
24+
25+
<activity
26+
android:name=".DarkAppCompatActivity"
27+
android:theme="@style/Theme.AppCompatThemeTest" />
28+
29+
<activity
30+
android:name=".NotAppCompatActivity"
31+
android:theme="@android:style/Theme.Material" />
32+
</application>
33+
34+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2021 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.accompanist.appcompattheme
18+
19+
import androidx.appcompat.app.AppCompatActivity
20+
import org.junit.runner.RunWith
21+
import org.robolectric.ParameterizedRobolectricTestRunner
22+
23+
/**
24+
* Version of [BaseAppCompatThemeTest] which is designed to be run using Robolectric.
25+
*
26+
* All of the tests are provided by [BaseAppCompatThemeTest].
27+
*/
28+
@RunWith(ParameterizedRobolectricTestRunner::class)
29+
class RobolectricAppCompatThemeTest<T : AppCompatActivity>(
30+
activityClass: Class<T>
31+
) : BaseAppCompatThemeTest<T>(activityClass) {
32+
companion object {
33+
@JvmStatic
34+
@ParameterizedRobolectricTestRunner.Parameters
35+
fun activities() = listOf(
36+
DarkAppCompatActivity::class.java,
37+
LightAppCompatActivity::class.java
38+
)
39+
}
40+
}

0 commit comments

Comments
 (0)