Skip to content

Commit 025dd17

Browse files
authored
ui automator added to espresso
1 parent 896c0f7 commit 025dd17

File tree

1 file changed

+111
-3
lines changed

1 file changed

+111
-3
lines changed

_drafts/2019-02-04-espresso.md

Lines changed: 111 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ categories: ["Testowanie"]
66
image: testing/espresso
77
github: testing/tree/master/espresso
88
description: "Testowanie"
9-
version: Espresso v3.1
10-
keywords: "testowanie, testing, testy, jednostkowe, integracyjne, manualne, ui, automatyczne, instrumentalne, zaślepka, atrapa, unit test, mock, stub, espresso, android, programowanie, programming"
9+
version: Espresso v3.1, UI Automator v2.2
10+
keywords: "testowanie, testing, testy, jednostkowe, integracyjne, manualne, ui, automatyczne, instrumentalne, unit test, espresso, uiautomator, android, programowanie, programming"
1111
---
1212

1313
## Testy UI
@@ -46,6 +46,14 @@ class MainActivity : AppCompatActivity() {
4646
startActivity(intent)
4747
}
4848

49+
buttonSms.setOnClickListener {
50+
val sendIntent = Intent(Intent.ACTION_VIEW)
51+
sendIntent.data = Uri.parse("sms:")
52+
sendIntent.putExtra("address", "111222333")
53+
sendIntent.putExtra("sms_body", textViewName.text)
54+
startActivity(sendIntent)
55+
}
56+
4957
initListView()
5058
}
5159

@@ -161,4 +169,104 @@ class VerifyTest {
161169
onView(withId(R.id.textViewName)).check(matches(not(isDisplayed())))
162170
}
163171
}
164-
{% endhighlight %}
172+
{% endhighlight %}
173+
174+
## UI Automator
175+
Testy przeprowadzane w `UI Automator` pozwalają na weryfikację zachowania testowanej w aplikacji w interakcjach z innymi aplikacjami lub komponentami systemu. Przebiegają wg podobnego scenariusza co testy w `Espresso`, tzn. znajdowany jest widok, wykonywane są akcje i finalnie następuje sprawdzenie poprawności oczekiwanego stanu. Na wstępie jednak trzeba uzyskać dostęp do testowanego urządzenia poprzez instancję `UiDevice` dzięki czemu możliwe jest znajdowanie i operowanie na widokach oraz manipulowanie stanem urządzania. Dobrą praktyką jest rozpoczynanie testów od głównego ekranu systemowego.
176+
177+
{% highlight kotlin %}
178+
@RunWith(AndroidJUnit4::class)
179+
class UIAutomatorTest {
180+
181+
private val APP_PACKAGE = "pl.androidcode"
182+
private val SMS_APP_PACKAGE = "com.google.android.apps.messaging"
183+
184+
private lateinit var device: UiDevice
185+
186+
@Before
187+
fun startMainActivityFromHomeScreen() {
188+
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) //initialize
189+
device.pressHome() //start every test from home screen
190+
deviceWait(device.launcherPackageName) //wait for launcher
191+
192+
//start the app
193+
val context = ApplicationProvider.getApplicationContext<Context>()
194+
val intent = context.packageManager.getLaunchIntentForPackage(APP_PACKAGE)
195+
.apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) }
196+
context.startActivity(intent)
197+
deviceWait(APP_PACKAGE) //wait for app
198+
}
199+
200+
private fun deviceWait(pkg: String) {
201+
device.wait(Until.hasObject(By.pkg(pkg).depth(0)), 5000L)
202+
}
203+
204+
//some tests
205+
}
206+
{% endhighlight %}
207+
208+
Aby otrzymać dostęp do komponentów widoków aplikacji (widocznych na ekranie) należy uzyskać instancję typu `UiObject` wywołując metodę `findObject` na obiekcie `UiDevice` przekazując jako argument odpowiedni `UiSelector` konstruowany na podstawie m.in. id (`resourceId`), zawartości (`text`) czy nazwy klasy obiektu widoku (`className`). O ile komplet informacji nt widoków testowanej aplikacji dostępny jest z poziomu kodu to w przypadku zewnętrznych aplikacji i komponentów systemu już niekoniecznie. W takim przypadku można posłużyć się narzędziem `UI Automator Viewer` dostępnym w `Android Studio`. Akcje jakie można wykonać to m.in. `click`, `dragTo`, `setText`, `swipeUp`.
209+
210+
{% highlight kotlin %}
211+
@Test
212+
fun verifyTypedMessageFromEditText() {
213+
//find views by some selectors (known from you app code)
214+
val editText = device.findObject(UiSelector().resourceId("${APP_PACKAGE}:id/editTextName"))
215+
val buttonAction = device.findObject(UiSelector().text("ACTION").className("android.widget.Button"))
216+
val buttonSms = device.findObject(UiSelector().text("SMS").className("android.widget.Button"))
217+
218+
if(editText.exists() && buttonAction.exists() && buttonSms.exists()) {
219+
//do actions
220+
editText.setText("message")
221+
buttonAction.click()
222+
buttonSms.click()
223+
deviceWait(SMS_APP_PACKAGE) //wait for expected sms app
224+
225+
//find view by some selectors (known from UiAutomator Viewer)
226+
val messageField = device.findObject(UiSelector().resourceId("${SMS_APP_PACKAGE}:id/compose_message_text"))
227+
Assert.assertEquals("message", messageField.text)
228+
}
229+
else throw UiObjectNotFoundException("Throw when no matching UI element is found")
230+
}
231+
{% endhighlight %}
232+
233+
Symulowanie interakcji z elementami kolekcji lub komponentami typu scrollable może odbywać się przy użyciu klas `UiCollection` i `UiScrollable`.
234+
235+
{% highlight kotlin %}
236+
/*instead of findObject on UiDevice like below UiCollection and UiScrollable can be used
237+
val listViewItem: UiObject = device.findObject(UiSelector().className("android.widget.ListView")
238+
.instance(0).childSelector(UiSelector().text("name1")))*/
239+
240+
@Test
241+
fun verifyPassedMessageFromCollection() {
242+
val buttonSms = device.findObject(UiSelector().text("SMS").className("android.widget.Button"))
243+
val collection: UiCollection = UiCollection(UiSelector().className("android.widget.ListView"))
244+
val listViewItem: UiObject = collection.getChild(UiSelector().text("name1"))
245+
246+
if(listViewItem.exists() && buttonSms.exists()) {
247+
listViewItem.click()
248+
buttonSms.click()
249+
deviceWait(SMS_APP_PACKAGE) //wait for expected sms app
250+
251+
val messageField = device.findObject(UiSelector().resourceId("${SMS_APP_PACKAGE}:id/compose_message_text"))
252+
Assert.assertEquals("name1", messageField.text)
253+
}
254+
else throw UiObjectNotFoundException("Throw when no matching UI element is found")
255+
}
256+
257+
@Test
258+
fun verifyPassedMessageFromScrollable() {
259+
val buttonSms = device.findObject(UiSelector().text("SMS").className("android.widget.Button"))
260+
val scrollable = UiScrollable(UiSelector().className("android.widget.ListView"))
261+
262+
if(buttonSms.exists()) {
263+
scrollable.getChildByText(UiSelector().className("android.widget.TextView"), "name1")
264+
buttonSms.click()
265+
deviceWait(SMS_APP_PACKAGE) //wait for expected sms app
266+
267+
val messageField = device.findObject(UiSelector().resourceId("${SMS_APP_PACKAGE}:id/compose_message_text"))
268+
Assert.assertEquals("name1", messageField.text)
269+
}
270+
else throw UiObjectNotFoundException("Throw when no matching UI element is found")
271+
}
272+
{% endhighlight %}

0 commit comments

Comments
 (0)