Espresso Web

Espresso-Web은 Android WebView UI 구성요소를 사용하기 위한 진입점입니다. Espresso-Web은 인기 WebDriver API의 Atom을 재사용하여 WebView의 동작을 검사하고 제어합니다.

Espresso-Web 사용 시기

하이브리드 앱, 특히 앱의 네이티브 UI 구성요소와 WebView UI 구성요소의 통합을 테스트하려면 Espresso-Web을 사용하세요. Espresso-Web API를 다른 Espresso API와 함께 사용하여 WebView 객체 내의 웹 요소와 완벽하게 상호작용할 수 있습니다.

앱의 WebView과 네이티브 구성요소 간의 상호작용이 아니라 WebView 자체만 테스트해야 한다면 WebDriver와 같은 프레임워크를 사용하여 일반적인 웹 테스트를 작성해 보세요. 웹 테스트 프레임워크를 사용하면 Android 기기나 자바 가상 머신을 사용할 필요가 없으므로 테스트가 더 빠르고 안정적으로 실행됩니다. 즉, Espresso-Web을 사용하면 맞춤 WebDriver Atom을 재사용할 수 있으므로 특히 독립형 웹 앱과 Android UI를 포함하는 앱 모두에서 실행할 테스트를 작성할 때 유연성이 크게 향상됩니다.

작동 방식

Espresso의 onData() 메서드와 마찬가지로 WebView 상호작용은 여러 개의 Atom으로 구성됩니다. WebView 상호작용은 자바 프로그래밍 언어와 JavaScript 브리지의 조합을 사용하여 작업을 실행합니다. JavaScript 환경에서 데이터를 노출하여 경합 상태가 발생할 가능성이 없으므로(Espresso가 자바 기반 측에서 보는 모든 항목은 격리된 사본임) Web.WebInteraction 객체에서 데이터 반환이 완전히 지원되므로 요청에서 반환된 모든 데이터를 확인할 수 있습니다.

WebDriver Atom이란?

WebDriver 프레임워크는 Atom을 사용하여 프로그래매틱 방식으로 웹 요소를 찾고 조작합니다. Atom은 WebDriver에서 브라우저 조작을 허용하는 데 사용됩니다. Atom은 개념적으로 UI에서 작업을 실행하는 독립 실행형 단위인 ViewAction와 유사합니다. findElement()getElement()와 같은 정의된 메서드 목록을 사용하여 Atom을 노출하여 사용자의 관점에서 브라우저를 구동합니다. 그러나 WebDriver 프레임워크를 직접 사용하는 경우 Atom을 올바르게 조정해야 하므로 매우 상세한 로직이 필요합니다.

Espresso 내에서 WebWeb.WebInteraction 클래스는 이 상용구를 래핑하고 Espresso에서 WebView 객체와 상호작용하는 것과 같은 느낌을 줍니다. 따라서 WebView의 컨텍스트에서 Atom은 기존 Espresso ViewMatchersViewActions 대신 사용됩니다.

그러면 다음과 같이 API가 매우 단순해집니다.

Kotlin

onWebView()
    .withElement(Atom)
    .perform(Atom)
    .check(WebAssertion)

Java

onWebView()
    .withElement(Atom)
    .perform(Atom)
    .check(WebAssertion);

자세히 알아보려면 Atom에 관한 Selenium 문서를 읽어보세요.

WebView 구현

앱 테스트에서 WebView를 사용하려면 다음 섹션에 나온 안내를 따르세요.

택배

Espresso-Web을 프로젝트에 포함하려면 다음 단계를 완료하세요.

  1. 앱의 build.gradle 파일을 엽니다. 이 파일은 일반적으로 최상위 수준의 build.gradle 파일이 아니라 app/build.gradle입니다.
  2. 종속 항목 내부에 다음 행을 추가합니다.

    Groovy

        androidTestImplementation 'androidx.test.espresso:espresso-web:3.4.0'
        

    Kotlin

        androidTestImplementation('androidx.test.espresso:espresso-web:3.4.0')
        
  3. Espresso-Web은 Espresso 2.2 이상 및 버전 0.3 이상의 테스트 라이브러리와만 호환되므로 이러한 줄도 업데이트해야 합니다.

    Groovy

        androidTestImplementation 'androidx.test:runner:1.4.0'
        androidTestImplementation 'androidx.test:rules:1.4.0'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
        

    Kotlin

        androidTestImplementation('androidx.test:runner:1.4.0')
        androidTestImplementation('androidx.test:rules:1.4.0')
        androidTestImplementation('androidx.test.espresso:espresso-core:3.4.0')
        

일반적인 API 사용

onWebView() 메서드는 Espresso를 사용하여 Android에서 WebView로 작업할 때 기본 진입점입니다. 이 메서드를 사용하여 다음과 같은 Espresso-Web 테스트를 실행할 수 있습니다.

Kotlin

onWebView()
    .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...))
    .perform(webClick()) // Similar to perform(click())

    // Similar to check(matches(...))
    .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")))

Java

onWebView()
    .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...))
    .perform(webClick()) // Similar to perform(click())

    // Similar to check(matches(...))
    .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")));

이 예에서 Espresso-Web은 ID가 "link_2"인 DOM 요소를 찾아 클릭합니다. 그런 다음 이 도구는 WebView가 "navigation_2.html" 문자열을 포함하는 GET 요청을 전송하는지 확인합니다.

자바스크립트 지원

테스트를 실행할 때 시스템은 JavaScript를 사용하여 모든 WebView 상호작용을 실행합니다. 따라서 자바스크립트 평가를 지원하려면 테스트 중인 WebView에서 자바스크립트를 사용 설정해야 합니다.

다음 코드 스니펫에서와 같이 테스트 중인 활동의 작업으로 forceJavascriptEnabled()를 호출하여 JavaScript를 강제로 사용 설정할 수 있습니다.

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule val activityScenarioRule =
        activityScenarioRule<MyWebViewActivity>()

    @Test fun testWebViewInteraction() {
        onWebView().forceJavascriptEnabled()
    }
}

일반적인 웹 상호작용

Web.WebInteraction 객체와의 일반적인 상호작용에는 다음이 포함됩니다.

  • withElement()는 WebView 내에서 DOM 요소를 참조합니다.

    예:

    Kotlin

    onWebView().withElement(findElement(Locator.ID, "teacher"))
    

    Java

    onWebView().withElement(findElement(Locator.ID, "teacher"));
    
  • withContextualElement()는 WebView 내에서 다른 DOM 요소와 관련하여 범위가 지정된 DOM 요소를 참조합니다. 참조 Web.WebInteraction 객체 (DOM 요소)를 설정하려면 먼저 withElement()를 호출해야 합니다.

    예:

    Kotlin

    .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"))
    

    Java

    .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"));
    
  • check()는 조건을 평가하여 true로 확인되는지 확인합니다.

    예:

    Kotlin

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"))
        .check(webMatches(getText(), containsString("Socrates")))
    

    Java

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .withContextualElement(findElement(Locator.ID, "person_name"))
        .check(webMatches(getText(), containsString("Socrates")));
    
  • perform()는 WebView 내에서 요소 클릭과 같은 작업을 실행합니다.

    예:

    Kotlin

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .perform(webClick())
    

    Java

    onWebView()
        .withElement(findElement(Locator.ID, "teacher"))
        .perform(webClick());
    
  • reset()는 WebView를 초기 상태로 되돌립니다. 이는 클릭과 같은 이전 작업으로 인해 ElementReference 및 WindowReference 객체에 액세스할 수 없게 하는 탐색 변경이 발생할 때 필요합니다.

    참고: reset()를 사용하면 양식 제출과 같은 다중 페이지 워크플로에 관해 어설션할 때 유용하지만 일반적으로 테스트 범위는 제한되고 단일 페이지에 중점을 두어야 합니다.

    예:

    Kotlin

    onWebView()
        .withElement(...)
        .perform(...)
        .reset()
    

    Java

    onWebView()
        .withElement(...)
        .perform(...)
        .reset();
    

다음 예에서는 WebView에 텍스트를 입력하고 Submit 버튼을 선택한 후 동일한 WebView의 다른 요소 내에 동일한 텍스트가 표시되는지 테스트합니다.

Kotlin

const val MACCHIATO = "Macchiato"

@RunWith(AndroidJUnit4::class)
class MyEspressoWebTestSuite {

    @Test fun typeTextInInput_clickButton_SubmitsForm() {
        // Create an intent that displays a web form.
        val webFormIntent = Intent()
        // ...

        // Lazily launch the Activity with a custom start Intent per test.
        ActivityScenario.launchActivity(webFormIntent)

        // Selects the WebView in your layout. If you have multiple WebView
        // objects, you can also use a matcher to select a given WebView,
        // onWebView(withId(R.id.web_view)).
        onWebView()
            // Find the input element by ID.
            .withElement(findElement(Locator.ID, "text_input"))

            // Clear previous input and enter new text into the input element.
            .perform(clearElement())
            .perform(DriverAtoms.webKeys(MACCHIATO))

            // Find the "Submit" button and simulate a click using JavaScript.
            .withElement(findElement(Locator.ID, "submitBtn"))
            .perform(webClick())

            // Find the response element by ID, and verify that it contains the
            // entered text.
            .withElement(findElement(Locator.ID, "response"))
            .check(webMatches(getText(), containsString(MACCHIATO)))
    }
}

Java

public static final String MACCHIATO = "Macchiato";

@Test
public void typeTextInInput_clickButton_SubmitsForm() {
    // Create an intent that displays a web form.
    Intent webFormIntent = new Intent();
    // ...

    // Lazily launch the Activity with a custom start Intent per test.
    ActivityScenario.launchActivity(webFormIntent);

    // Selects the WebView in your layout. If you have multiple WebView objects,
    // you can also use a matcher to select a given WebView,
    // onWebView(withId(R.id.web_view)).
    onWebView()
        // Find the input element by ID.
        .withElement(findElement(Locator.ID, "text_input"))

        // Clear previous input and enter new text into the input element.
        .perform(clearElement())
        .perform(DriverAtoms.webKeys(MACCHIATO))

        // Find the "Submit" button and simulate a click using JavaScript.
        .withElement(findElement(Locator.ID, "submitBtn"))
        .perform(webClick())

        // Find the response element by ID, and verify that it contains the
        // entered text.
        .withElement(findElement(Locator.ID, "response"))
        .check(webMatches(getText(), containsString(MACCHIATO)));
}

추가 리소스

Android 테스트에서 Espresso-Web을 사용하는 방법에 관한 자세한 내용은 다음 리소스를 참조하세요.

샘플

  • WebBasicSample: Espresso-Web을 사용하여 WebView 객체와 상호작용합니다.