Skip to content

Commit bbb6df1

Browse files
enhance instrumented tests
1 parent d367960 commit bbb6df1

File tree

10 files changed

+116
-137
lines changed

10 files changed

+116
-137
lines changed

.github/workflows/android_ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ jobs:
2828
with:
2929
token: ${{ secrets.CODECOV_TOKEN }}
3030
file: ./app/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml
31+
- name: run instrumented tests
32+
run: bash ./gradlew connectedAndroidTest --stacktrace
3133
- name: build apk
3234
run: bash ./gradlew assembleDebug --stacktrace
3335
- name: artifact apk
3436
uses: actions/upload-artifact@v4
3537
with:
3638
name: artifact-apk
37-
path: app/build/outputs/apk/debug
39+
path: app/build/outputs/apk/debug

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ dependencies {
5757
// Android Test Dependencies
5858
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
5959
androidTestImplementation 'androidx.test.ext:junit-ktx:1.2.1'
60+
androidTestImplementation 'androidx.test:rules:1.6.1'
6061
}
6162

6263
android {

app/build.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#Build Properties
2-
#Mon Mar 31 19:38:42 EDT 2025
3-
version_build=3
2+
#Mon Mar 31 20:38:21 EDT 2025
3+
version_build=4
44
version_major=3
55
version_minor=2
66
version_patch=0

app/jacoco.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ task jacocoTestCoverageVerification(type: JacocoCoverageVerification, dependsOn:
7070
}
7171
limit {
7272
counter = 'BRANCH'
73-
minimum = 0.87
73+
minimum = 0.88
7474
}
7575
limit {
7676
counter = 'COMPLEXITY'

app/src/androidTest/kotlin/com/vrem/wifianalyzer/FilterInstrumentedTest.kt

Lines changed: 8 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,59 +17,16 @@
1717
*/
1818
package com.vrem.wifianalyzer
1919

20-
import androidx.test.espresso.Espresso
21-
import androidx.test.espresso.action.ViewActions
22-
import androidx.test.espresso.matcher.ViewMatchers
23-
import org.hamcrest.Matchers
20+
import androidx.test.espresso.Espresso.onView
21+
import androidx.test.espresso.action.ViewActions.click
22+
import androidx.test.espresso.action.ViewActions.scrollTo
23+
import androidx.test.espresso.matcher.ViewMatchers.withId
2424

2525
internal class FilterInstrumentedTest : Runnable {
2626
override fun run() {
27-
actionOpen()
28-
actionClose()
29-
}
30-
31-
private fun actionClose() {
32-
pauseLong()
33-
Espresso.onView(
34-
Matchers.allOf(
35-
ViewMatchers.withId(android.R.id.button3),
36-
ViewMatchers.withText(FILTER_CLOSE_TAG),
37-
ChildAtPosition(
38-
ChildAtPosition(
39-
ViewMatchers.withClassName(Matchers.`is`("android.widget.ScrollView")),
40-
FILTER_BUTTON_CLOSE
41-
), FILTER_ACTION
42-
)
43-
)
44-
)
45-
.perform(ViewActions.scrollTo(), ViewActions.click())
46-
}
47-
48-
private fun actionOpen() {
27+
onView(withId(R.id.action_filter)).perform(click())
28+
pauseShort()
29+
onView(withId(android.R.id.button3)).perform(scrollTo(), click())
4930
pauseShort()
50-
Espresso.onView(
51-
Matchers.allOf(
52-
ViewMatchers.withId(R.id.action_filter),
53-
ViewMatchers.withContentDescription(FILTER_BUTTON_TAG),
54-
ChildAtPosition(
55-
ChildAtPosition(
56-
ViewMatchers.withId(R.id.toolbar),
57-
FILTER_BUTTON_OPEN
58-
),
59-
FILTER_ACTION
60-
),
61-
ViewMatchers.isDisplayed()
62-
)
63-
)
64-
.perform(ViewActions.click())
65-
}
66-
67-
68-
companion object {
69-
private const val FILTER_BUTTON_OPEN = 2
70-
private const val FILTER_BUTTON_CLOSE = 0
71-
private const val FILTER_ACTION = 0
72-
private const val FILTER_BUTTON_TAG = "Filter"
73-
private const val FILTER_CLOSE_TAG = "Close"
7431
}
75-
}
32+
}

app/src/androidTest/kotlin/com/vrem/wifianalyzer/InstrumentedTestUtils.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ package com.vrem.wifianalyzer
1919

2020
import android.view.View
2121
import android.view.ViewGroup
22+
import androidx.appcompat.widget.Toolbar
2223
import androidx.test.espresso.Espresso
24+
import androidx.test.espresso.matcher.BoundedMatcher
2325
import org.hamcrest.Description
2426
import org.hamcrest.Matcher
2527
import org.hamcrest.TypeSafeMatcher
@@ -36,6 +38,17 @@ internal class ChildAtPosition(private val parentMatcher: Matcher<View>, private
3638
}
3739
}
3840

41+
internal fun withToolbarTitle(expectedTitle: CharSequence): Matcher<View> {
42+
return object : BoundedMatcher<View, Toolbar>(Toolbar::class.java) {
43+
override fun describeTo(description: Description) {
44+
description.appendText("with toolbar title: $expectedTitle")
45+
}
46+
47+
override fun matchesSafely(toolbar: Toolbar): Boolean =
48+
toolbar.title == expectedTitle
49+
}
50+
}
51+
3952
private const val SLEEP_TIME_SHORT = 5000
4053
private const val SLEEP_TIME_LONG = SLEEP_TIME_SHORT * 3
4154

app/src/androidTest/kotlin/com/vrem/wifianalyzer/MainInstrumentedTest.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule
2121
import androidx.test.ext.junit.rules.activityScenarioRule
2222
import androidx.test.ext.junit.runners.AndroidJUnit4
2323
import androidx.test.filters.LargeTest
24+
import androidx.test.rule.GrantPermissionRule
2425
import org.junit.Rule
2526
import org.junit.Test
2627
import org.junit.runner.RunWith
@@ -32,24 +33,27 @@ class MainInstrumentedTest {
3233
@get:Rule
3334
val activityTestRule: ActivityScenarioRule<MainActivity> = activityScenarioRule()
3435

36+
@get:Rule
37+
val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(
38+
android.Manifest.permission.ACCESS_COARSE_LOCATION,
39+
android.Manifest.permission.ACCESS_FINE_LOCATION,
40+
android.Manifest.permission.ACCESS_WIFI_STATE,
41+
android.Manifest.permission.CHANGE_WIFI_STATE,
42+
android.Manifest.permission.NEARBY_WIFI_DEVICES
43+
)
44+
3545
@Test
3646
fun navigation() {
37-
pauseShort()
3847
NavigationInstrumentedTest().run()
39-
pauseShort()
4048
}
4149

4250
@Test
4351
fun scanner() {
44-
pauseShort()
4552
ScannerInstrumentedTest().run()
46-
pauseShort()
4753
}
4854

4955
@Test
5056
fun filter() {
51-
pauseShort()
5257
FilterInstrumentedTest().run()
53-
pauseShort()
5458
}
5559
}

app/src/androidTest/kotlin/com/vrem/wifianalyzer/NavigationInstrumentedTest.kt

Lines changed: 49 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,71 +17,73 @@
1717
*/
1818
package com.vrem.wifianalyzer
1919

20-
import androidx.test.espresso.Espresso
21-
import androidx.test.espresso.action.ViewActions
22-
import androidx.test.espresso.matcher.ViewMatchers
20+
import androidx.appcompat.widget.Toolbar
21+
import androidx.test.espresso.Espresso.onView
22+
import androidx.test.espresso.action.ViewActions.click
23+
import androidx.test.espresso.assertion.ViewAssertions.matches
24+
import androidx.test.espresso.matcher.ViewMatchers.*
2325
import org.hamcrest.Matchers
26+
import org.hamcrest.Matchers.allOf
27+
28+
private const val NAVIGATION_DRAWER_BUTTON = 0
29+
private const val NAVIGATION_DRAWER_ACTION = 1
30+
private const val NAVIGATION_DRAWER_TAG = "Open navigation drawer"
2431

2532
internal class NavigationInstrumentedTest : Runnable {
33+
2634
override fun run() {
27-
selectMenuItem(CHANNEL_RATING)
28-
selectMenuItem(CHANNEL_GRAPH)
29-
selectMenuItem(TIME_GRAPH)
30-
pauseLong()
31-
selectMenuItem(AVAILABLE_CHANNELS)
32-
selectMenuItem(VENDORS)
33-
selectMenuItem(ACCESS_POINTS)
34-
selectMenuItem(SETTINGS)
35-
pressBackButton()
36-
selectMenuItem(ABOUT)
37-
pressBackButton()
35+
listOf(
36+
2 to "Channel Rating",
37+
3 to "Channel Graph",
38+
4 to "Time Graph",
39+
1 to "Access Points",
40+
7 to "Available Channels",
41+
8 to "Vendors"
42+
).forEach { (id, title) ->
43+
selectMenuItem(id, title)
44+
pauseShort()
45+
}
46+
listOf(
47+
10 to "Settings",
48+
11 to "About"
49+
).forEach { (id, title) ->
50+
selectMenuItem(id, title)
51+
pauseShort()
52+
pressBackButton()
53+
}
3854
}
3955

40-
private fun selectMenuItem(menuItem: Int) {
41-
pauseShort()
42-
val appCompatImageButton = Espresso.onView(
43-
Matchers.allOf(
44-
ViewMatchers.withContentDescription(NAVIGATION_DRAWER_TAG),
56+
private fun selectMenuItem(menuItem: Int, expectedTitle: String) {
57+
onView(
58+
allOf(
59+
withContentDescription(NAVIGATION_DRAWER_TAG),
4560
ChildAtPosition(
46-
Matchers.allOf(
47-
ViewMatchers.withId(R.id.toolbar),
61+
allOf(
62+
withId(R.id.toolbar),
4863
ChildAtPosition(
49-
ViewMatchers.withClassName(Matchers.`is`("com.google.android.material.appbar.AppBarLayout")),
64+
withClassName(Matchers.`is`("com.google.android.material.appbar.AppBarLayout")),
5065
NAVIGATION_DRAWER_BUTTON
5166
)
5267
),
5368
NAVIGATION_DRAWER_ACTION
5469
),
55-
ViewMatchers.isDisplayed()
70+
isDisplayed()
5671
)
57-
)
58-
appCompatImageButton.perform(ViewActions.click())
59-
pauseShort()
60-
val navigationMenuItemView = Espresso.onView(
61-
Matchers.allOf(
72+
).check(matches(isDisplayed())).perform(click())
73+
74+
onView(
75+
allOf(
6276
ChildAtPosition(
63-
Matchers.allOf(
64-
ViewMatchers.withId(com.google.android.material.R.id.design_navigation_view),
65-
ChildAtPosition(ViewMatchers.withId(R.id.nav_drawer), NAVIGATION_DRAWER_BUTTON)
77+
allOf(
78+
withId(com.google.android.material.R.id.design_navigation_view),
79+
ChildAtPosition(withId(R.id.nav_drawer), NAVIGATION_DRAWER_BUTTON)
6680
), menuItem
6781
),
68-
ViewMatchers.isDisplayed()
82+
isDisplayed()
6983
)
70-
)
71-
navigationMenuItemView.perform(ViewActions.click())
72-
}
84+
).check(matches(isDisplayed())).perform(click())
7385

74-
companion object {
75-
private const val ACCESS_POINTS = 1
76-
private const val CHANNEL_RATING = 2
77-
private const val CHANNEL_GRAPH = 3
78-
private const val TIME_GRAPH = 4
79-
private const val AVAILABLE_CHANNELS = 7
80-
private const val VENDORS = 8
81-
private const val SETTINGS = 10
82-
private const val ABOUT = 11
83-
private const val NAVIGATION_DRAWER_BUTTON = 0
84-
private const val NAVIGATION_DRAWER_ACTION = 1
85-
private const val NAVIGATION_DRAWER_TAG = "Open navigation drawer"
86+
onView(isAssignableFrom(Toolbar::class.java)).check(matches(withToolbarTitle(expectedTitle)))
8687
}
88+
8789
}

app/src/androidTest/kotlin/com/vrem/wifianalyzer/ScannerInstrumentedTest.kt

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,38 +17,24 @@
1717
*/
1818
package com.vrem.wifianalyzer
1919

20-
import androidx.test.espresso.Espresso
21-
import androidx.test.espresso.action.ViewActions
22-
import androidx.test.espresso.matcher.ViewMatchers
23-
import org.hamcrest.Matchers
20+
import androidx.test.espresso.Espresso.onView
21+
import androidx.test.espresso.action.ViewActions.click
22+
import androidx.test.espresso.matcher.ViewMatchers.*
23+
import com.vrem.wifianalyzer.R.id.action_scanner
24+
import org.hamcrest.Matchers.allOf
25+
26+
private const val PAUSE = "Pause"
27+
private const val PLAY = "Play"
2428

2529
internal class ScannerInstrumentedTest : Runnable {
26-
override fun run() {
27-
scannerAction(SCANNER_PAUSE_TAG)
28-
pauseLong()
29-
scannerAction(SCANNER_RESUME_TAG)
30-
}
3130

32-
private fun scannerAction(tag: String) {
31+
override fun run() {
32+
onView(allOf(withId(action_scanner), withContentDescription(PAUSE), isDisplayed())).perform(click())
33+
pauseShort()
34+
onView(allOf(withId(action_scanner), withContentDescription(PLAY), isDisplayed())).perform(click())
35+
pauseShort()
36+
onView(allOf(withId(action_scanner), withContentDescription(PAUSE), isDisplayed()))
3337
pauseShort()
34-
val actionMenuItemView = Espresso.onView(
35-
Matchers.allOf(
36-
ViewMatchers.withId(R.id.action_scanner),
37-
ViewMatchers.withContentDescription(tag),
38-
ChildAtPosition(
39-
ChildAtPosition(ViewMatchers.withId(R.id.toolbar), SCANNER_BUTTON),
40-
SCANNER_ACTION
41-
),
42-
ViewMatchers.isDisplayed()
43-
)
44-
)
45-
actionMenuItemView.perform(ViewActions.click())
4638
}
4739

48-
companion object {
49-
private const val SCANNER_BUTTON = 2
50-
private const val SCANNER_ACTION = 1
51-
private const val SCANNER_PAUSE_TAG = "Pause"
52-
private const val SCANNER_RESUME_TAG = "Play"
53-
}
5440
}

app/src/test/kotlin/com/vrem/wifianalyzer/wifi/band/WiFiChannelsTest.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class WiFiChannelsTest {
145145
}
146146

147147
@Test
148-
fun wiFiWidthUsingChannel() {
148+
fun wiFiWidthUsingChannelInRange() {
149149
fixtures.forEach { (wiFiBand, fixture) ->
150150
fixture.activeChannels.forEach { (wiFiWidth, channels) ->
151151
val expected = if (wiFiBand == WiFiBand.GHZ2 && wiFiWidth == WiFiWidth.MHZ_40) {
@@ -162,6 +162,20 @@ class WiFiChannelsTest {
162162
}
163163
}
164164

165+
@Test
166+
fun wiFiWidthUsingChannelNotInRange() {
167+
fixtures.forEach { (wiFiBand, fixture) ->
168+
val first = wiFiBand.wiFiChannels.channelRange.first.channel
169+
val last = wiFiBand.wiFiChannels.channelRange.second.channel
170+
assertThat(fixture.wiFiWidthByChannel(first - 1))
171+
.describedAs("$wiFiBand")
172+
.isEqualTo(WiFiWidth.MHZ_20)
173+
assertThat(fixture.wiFiWidthByChannel(last + 1))
174+
.describedAs("$wiFiBand")
175+
.isEqualTo(WiFiWidth.MHZ_20)
176+
}
177+
}
178+
165179
@Test
166180
fun availableChannels() {
167181
fixtures.forEach { (wiFiBand, fixture, expectedWiFiInfo) ->

0 commit comments

Comments
 (0)