

文件 AWS 開發套件範例 GitHub 儲存庫中有更多可用的 [AWS SDK 範例](https://github.com/awsdocs/aws-doc-sdk-examples)。

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Device Farm AWS SDKs的程式碼範例
<a name="device-farm_code_examples"></a>

下列程式碼範例示範如何 AWS Device Farm 搭配 AWS 軟體開發套件 (SDK) 使用 。

*Actions* 是大型程式的程式碼摘錄，必須在內容中執行。雖然動作會告訴您如何呼叫個別服務函數，但您可以在其相關情境中查看內容中的動作。

*案例*是向您展示如何呼叫服務中的多個函數或與其他 AWS 服務組合來完成特定任務的程式碼範例。

**其他資源**
+  **[Device Farm 開發人員指南](https://docs.aws.amazon.com/devicefarm/latest/developerguide/welcome.html)** – Device Farm 的詳細資訊。
+ **[Device Farm API 參考](https://docs.aws.amazon.com/devicefarm/latest/APIReference/Welcome.html)** – 所有可用 Device Farm 動作的詳細資訊。
+ **[AWS 開發人員中心](https://aws.amazon.com/developer/code-examples/?awsf.sdk-code-examples-product=product%23device-farm)** – 您可以依類別或全文搜尋篩選的程式碼範例。
+ **[AWS SDK 範例](https://github.com/awsdocs/aws-doc-sdk-examples)** – GitHub 儲存庫使用慣用語言的完整程式碼。包含設定和執行程式碼的指示。

**Contents**
+ [基本概念](device-farm_code_examples_basics.md)
  + [動作](device-farm_code_examples_actions.md)
    + [`CreateUpload`](device-farm_example_device-farm_CreateUpload_section.md)
+ [案例](device-farm_code_examples_scenarios.md)
  + [執行瀏覽器測試並取得螢幕擷取畫面](device-farm_example_device-farm_Scenario_BrowserTesting_section.md)
  + [上傳和測試裝置套件](device-farm_example_device-farm_Scenario_DeviceTesting_section.md)

# Device Farm AWS SDKs的基本範例
<a name="device-farm_code_examples_basics"></a>

下列程式碼範例示範如何 AWS Device Farm 搭配 AWS SDKs 使用 的基本概念。

**Contents**
+ [動作](device-farm_code_examples_actions.md)
  + [`CreateUpload`](device-farm_example_device-farm_CreateUpload_section.md)

# Device Farm AWS SDKs的動作
<a name="device-farm_code_examples_actions"></a>

下列程式碼範例示範如何使用 AWS SDKs 執行個別 Device Farm 動作。每個範例均包含 GitHub 的連結，您可以在連結中找到設定和執行程式碼的相關說明。

這些摘錄會呼叫 Device Farm API，是必須在內容中執行之大型程式的程式碼摘錄。您可以在 [Device Farm AWS SDKs的案例](device-farm_code_examples_scenarios.md) 中查看內容中的動作。

 下列範例僅包含最常使用的動作。如需完整清單，請參閱《[AWS Device Farm API 參考](https://docs.aws.amazon.com/devicefarm/latest/APIReference/Welcome.html)》。

**Topics**
+ [`CreateUpload`](device-farm_example_device-farm_CreateUpload_section.md)

# 搭配使用 `CreateUpload` 與 CLI
<a name="device-farm_example_device-farm_CreateUpload_section"></a>

下列程式碼範例示範如何使用 `CreateUpload`。

動作範例是大型程式的程式碼摘錄，必須在內容中執行。您可以在下列程式碼範例的內容中看到此動作：
+  [上傳和測試裝置套件](device-farm_example_device-farm_Scenario_DeviceTesting_section.md) 

------
#### [ CLI ]

**AWS CLI**  
**建立上傳**  
下列命令會為 Android 應用程式建立上傳：  

```
aws devicefarm create-upload --project-arn "arn:aws:devicefarm:us-west-2:123456789012:project:070fc3ca-7ec1-4741-9c1f-d3e044efc506" --name app.apk --type ANDROID_APP
```
您可以從 create-project 或 list-projects 的輸出中取得專案 ARN。  
輸出：  

```
{
    "upload": {
        "status": "INITIALIZED",
        "name": "app.apk",
        "created": 1503614408.769,
        "url": "https://prod-us-west-2-uploads.s3-us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A123456789012%3Aproject%3A070fc3ca-c7e1-4471-91cf-d3e4efc50604/uploads/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A123456789012%3Aupload%3A070fc3ca-7ec1-4741-9c1f-d3e044efc506/dd72723a-ae9e-4087-09e6-f4cea3599514/app.apk?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20170824T224008Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=AKIAEXAMPLEPBUMBC3GA%2F20170824%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Signature=05050370c38894ef5bd09f5d009f36fc8f96fa4bb04e1bba9aca71b8dbe49a0f",
        "type": "ANDROID_APP",
        "arn": "arn:aws:devicefarm:us-west-2:123456789012:upload:070fc3ca-7ec1-4741-9c1f-d3e044efc506/dd72723a-ae9e-4087-09e6-f4cea3599514"
    }
}
```
在輸出中使用已簽署的 URL，將檔案上傳至 Device Farm：  

```
curl -T app.apk "https://prod-us-west-2-uploads.s3-us-west-2.amazonaws.com/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A123456789012%3Aproject%3A070fc3ca-c7e1-4471-91cf-d3e4efc50604/uploads/arn%3Aaws%3Adevicefarm%3Aus-west-2%3A123456789012%3Aupload%3A070fc3ca-7ec1-4741-9c1f-d3e044efc506/dd72723a-ae9e-4087-09e6-f4cea3599514/app.apk?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20170824T224008Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=AKIAEXAMPLEPBUMBC3GA%2F20170824%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Signature=05050370c38894ef5bd09f5d009f36fc8f96fa4bb04e1bba9aca71b8dbe49a0f"
```
+  如需 API 詳細資訊，請參閱《AWS CLI 命令參考》**中的 [CreateUpload](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/devicefarm/create-upload.html)。

------
#### [ PowerShell ]

**Tools for PowerShell V4**  
**範例 1：此範例會為 Android 應用程式建立 AWS Device Farm 上傳。您可以從 New-DFProject 或 Get-DFProjectList 的輸出，取得專案 ARN。在 New-DFUpload 輸出中使用已簽署的 URL，將檔案上傳至 Device Farm。**  

```
New-DFUpload -ContentType "application/octet-stream" -ProjectArn "arn:aws:devicefarm:us-west-2:123456789012:project:EXAMPLEa-7ec1-4741-9c1f-d3e04EXAMPLE" -Name "app.apk" -Type ANDROID_APP
```
+  如需 API 詳細資訊，請參閱《AWS Tools for PowerShell Cmdlet 參考 (V4)》**中的 [CreateUpload](https://docs.aws.amazon.com/powershell/v4/reference)。

**Tools for PowerShell V5**  
**範例 1：此範例會為 Android 應用程式建立 AWS Device Farm 上傳。您可以從 New-DFProject 或 Get-DFProjectList 的輸出，取得專案 ARN。在 New-DFUpload 輸出中使用已簽署的 URL，將檔案上傳至 Device Farm。**  

```
New-DFUpload -ContentType "application/octet-stream" -ProjectArn "arn:aws:devicefarm:us-west-2:123456789012:project:EXAMPLEa-7ec1-4741-9c1f-d3e04EXAMPLE" -Name "app.apk" -Type ANDROID_APP
```
+  如需 API 詳細資訊，請參閱《AWS Tools for PowerShell Cmdlet 參考 (V5)》**中的 [CreateUpload](https://docs.aws.amazon.com/powershell/v5/reference)。

------

# Device Farm AWS SDKs的案例
<a name="device-farm_code_examples_scenarios"></a>

下列程式碼範例示範如何在 Device Farm AWS SDKs中實作常見案例。這些案例示範如何呼叫 Device Farm 中的多個函數，或與其他 AWS 服務結合，藉以完成特定任務。每個案例均包含完整原始碼的連結，您可在連結中找到如何設定和執行程式碼的相關指示。

案例的目標是獲得中等水平的經驗，協助您了解內容中的服務動作。

**Topics**
+ [執行瀏覽器測試並取得螢幕擷取畫面](device-farm_example_device-farm_Scenario_BrowserTesting_section.md)
+ [上傳和測試裝置套件](device-farm_example_device-farm_Scenario_DeviceTesting_section.md)

# 使用 Device Farm 執行瀏覽器測試，並使用 AWS SDK 擷取螢幕擷取畫面
<a name="device-farm_example_device-farm_Scenario_BrowserTesting_section"></a>

下列程式碼範例示範如何使用 Device Farm 執行瀏覽器測試，並取得螢幕擷取畫面。

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在 [AWS 程式碼範例儲存庫](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/devicefarm/browser_testing#code-examples)中設定和執行。
使用 PyTest 和 Selenium 瀏覽至指定的網站、取得螢幕擷取畫面，並將實際網站內容與預期內容做比較。  

```
import datetime
import os
import subprocess
import boto3
import pytest
from selenium import webdriver
from selenium.webdriver import DesiredCapabilities
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait


def get_git_hash():
    """
    Get the short Git hash of the current commit of the repository
    """
    try:
        return (
            subprocess.check_output(["git", "rev-parse", "--short", "HEAD"])
            .decode("utf-8")
            .strip()
        )
    except:
        return "norepo"


class TestHelloSuite:
    """
    Our test suite.

    This style of test suite allows us to use setup_method and teardown_method.

    """

    def save_screenshot(self, name):
        self.driver.save_screenshot(os.path.join(self.screenshot_path, name))

    def setup_method(self, method):
        """
        Set up a test.

        This makes sure that the session for an individual test is ready.

        The AWS credentials are read from the default ~/.aws/credentials or from the
        command line by setting the AWS_ACCESS_KEY_ID and AWS_SECRET_KEY environment
        variables.

        The project Amazon Resource Name (ARN) is determined by the PROJECT_ARN
        environment variable.
        """
        devicefarm_client = boto3.client("devicefarm")
        project_arn = os.environ.get("PROJECT_ARN", None)
        if project_arn is None:
            raise ValueError("Must set PROJECT_ARN")
        # Request a driver hub URL for the Selenium client
        testgrid_url_response = devicefarm_client.create_test_grid_url(
            projectArn=project_arn, expiresInSeconds=300
        )

        # We want a directory to save our files into. We're going to make a directory
        # in the current directory that holds our results.
        self.screenshot_path = os.path.join(
            ".", "results", get_git_hash() + "-" + (datetime.date.today().isoformat())
        )
        if not os.path.exists(self.screenshot_path):
            os.makedirs(self.screenshot_path, exist_ok=True)

        # We want a Firefox instance on Windows
        desired_cap = DesiredCapabilities.FIREFOX
        desired_cap["platform"] = "windows"
        desired_cap["BrowserVersion"] = "latest"

        # Configure the webdriver with the appropriate remote endpoint.
        self.driver = webdriver.Remote(testgrid_url_response["url"], desired_cap)

        #
        # Auto-Tagging
        #

        # In order to get the Session ARN, we need to look up the session by the
        # Project ARN and session ID (from the driver).
        testgrid_session_arn_response = devicefarm_client.get_test_grid_session(
            projectArn=project_arn, sessionId=self.driver.session_id
        )

        # Save the session's ARN so we can tag the session.
        self.session_arn = testgrid_session_arn_response["testGridSession"]["arn"]

        # In order to tag it, we're going to use the resourcegroupstaggingapi client to
        # add a tag to the session ARN that we just got.
        tag_client = boto3.client("resourcegroupstaggingapi")
        tag_client.tag_resources(
            ResourceARNList=[self.session_arn],
            Tags={"TestSuite": f"testsuite {method.__name__}", "GitId": get_git_hash()},
        )

    def teardown_method(self, method):
        """
        Clean up resources used by each method.
        """
        # End the Selenium session so we're off the clock.
        self.driver.quit()

    @pytest.mark.parametrize(
        "query,leading",
        [
            pytest.param(
                "Seattle",
                "Seattle (/siˈætəl/ (listen) see-AT-əl) is a seaport city on the West Coast of the United States.",
            ),
            pytest.param(
                "Selenium",
                "Selenium is a chemical element with the symbol Se and atomic number 34.",
            ),
            pytest.param(
                "Amazon Locker",
                "Amazon Locker is a self-service package delivery service offered by online retailer Amazon.",
            ),
            pytest.param(
                "Kootenai Falls",
                "Kootenai Falls is a waterfall on the Kootenay River located in Lincoln County, Montana, just off U.S. Route 2.",
            ),
            pytest.param(
                "Dorayaki",
                "Dorayaki (どら焼き, どらやき, 銅鑼焼き, ドラ焼き) is a type of Japanese confection.",
            ),
            pytest.param("Robot Face", "<|°_°|> (also known as Robot Face or Robot)"),
        ],
    )
    def test_first_paragraph_text(self, query, leading):
        """
        This test looks at the first paragraph of a page on Wikipedia, comparing it to
        a known leading sentence.

        If the leading sentence matches, the test passes. A screenshot is taken before
        the final assertion is made, letting us debug if something isn't right.
        """
        # Open the main page of Wikipedia
        self.driver.get("https://en.wikipedia.org/wiki/Main_Page")
        # Find the search box, enter a query, and press enter
        search_input = self.driver.find_element(By.ID, "searchInput")
        search_input.click()
        search_input.send_keys(query)
        search_input.send_keys(Keys.ENTER)
        # Wait for the search box to go stale -- This means we've navigated fully.
        WebDriverWait(self.driver, 5).until(
            expected_conditions.staleness_of(search_input)
        )
        # Get the leading paragraph of the article.
        lead = leading.lower()
        # Find the element...
        lead_para = self.driver.find_element(
            By.XPATH, "//div[@class='mw-parser-output']//p[not(@class)]"
        )
        # ... and copy out its text.
        our_text = lead_para.text.lower()
        our_text = our_text[: len(lead)]
        # Take a screenshot and compare the strings.
        self.save_screenshot(f"leadingpara_{query}.png")
        assert our_text.startswith(lead)

    @pytest.mark.parametrize(
        "query,expected",
        [
            pytest.param("Automation Testing", "Test Automation"),
            pytest.param("DevOps", "DevOps"),
            pytest.param("Jackdaws Love My Big Sphinx Of Quartz", "Pangram"),
            pytest.param("EarthBound", "EarthBound"),
            pytest.param("Covered Bridges Today", "Covered Bridges Today"),
            pytest.param("Kurt Godel", "Kurt Gödel"),
            pytest.param("N//ng language", "Nǁng language"),
            pytest.param(
                "Who the Frick Is Jackson Pollock?", "Who the $&% Is Jackson Pollock?"
            ),
        ],
    )
    def test_redirect_titles(self, query, expected):
        """
        A test comparing pages we expect to (or not to) redirect on Wikipedia.

        This test checks to see that the page ("query") redirects (or doesn't) to the
        "expected" page title. Several of these are common synonyms ("Jackdaws...")
        while others are because of characters untypable by most keyboards ("Nǁng language")

        A screenshot is taken just before the final assertion is made to aid in
        debugging and verification.
        """
        # Open the main page of Wikipedia
        self.driver.get("https://en.wikipedia.org/wiki/Main_Page")
        # Find the search box, enter some text into it, and send an enter key.
        search_input = self.driver.find_element(By.ID, "searchInput")
        search_input.click()
        search_input.send_keys(query)
        search_input.send_keys(Keys.ENTER)
        # wait until the page has rolled over -- once the search input handle is stale,
        # the browser has navigated.
        WebDriverWait(self.driver, 5).until(
            expected_conditions.staleness_of(search_input)
        )
        # Get the first heading & take a screenshot
        our_text = self.driver.find_element(By.ID, "firstHeading").text.lower()
        self.save_screenshot(f"redirect_{query}.png")
        # did it match?
        assert our_text == expected.lower()
```
+ 如需 API 詳細資訊，請參閱《適用於 Python (Boto3) 的AWS SDK API 參考》**中的下列主題。
  + [CreateTestGridUrl](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/CreateTestGridUrl)
  + [GetTestGridSession](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/GetTestGridSession)

------

# 使用 AWS SDK 透過 Device Farm 上傳和測試行動裝置套件
<a name="device-farm_example_device-farm_Scenario_DeviceTesting_section"></a>

下列程式碼範例示範如何使用 Device Farm 上傳和測試行動裝置套件。

------
#### [ Python ]

**適用於 Python 的 SDK (Boto3)**  
 GitHub 上提供更多範例。尋找完整範例，並了解如何在 [AWS 程式碼範例儲存庫](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/devicefarm/device_testing#code-examples)中設定和執行。
將已編譯的 Android 應用程式和測試套件上傳至 Device Farm、開始測試、等待測試完成，然後報告結果。  

```
import boto3
import os
import requests
import string
import random
import datetime
import time

# Update this dict with your own values before you run the example:
config = {
    # This is our app under test.
    "appFilePath": "app-debug.apk",
    "projectArn": "arn:aws:devicefarm:us-west-2:111222333444:project:581f5703-e040-4ac9-b7ae-0ba007bfb8e6",
    # Since we care about the most popular devices, we'll use a curated pool.
    "testSpecArn": "arn:aws:devicefarm:us-west-2::upload:20fcf771-eae3-4137-aa76-92e17fb3131b",
    "poolArn": "arn:aws:devicefarm:us-west-2::devicepool:4a869d91-6f17-491f-9a95-0a601aee2406",
    "namePrefix": "MyAppTest",
    # This is our test package. This tutorial won't go into how to make these.
    "testPackage": "tests.zip",
}

client = boto3.client("devicefarm")

unique = (
    config["namePrefix"]
    + "-"
    + (datetime.date.today().isoformat())
    + ("".join(random.sample(string.ascii_letters, 8)))
)

print(
    f"The unique identifier for this run is '{unique}'. All uploads will be prefixed "
    f"with this."
)


def upload_df_file(filename, type_, mime="application/octet-stream"):
    upload_response = client.create_upload(
        projectArn=config["projectArn"],
        name=unique + "_" + os.path.basename(filename),
        type=type_,
        contentType=mime,
    )
    upload_arn = upload_response["upload"]["arn"]
    # Extract the URL of the upload and use Requests to upload it.
    upload_url = upload_response["upload"]["url"]
    with open(filename, "rb") as file_stream:
        print(
            f"Uploading {filename} to Device Farm as "
            f"{upload_response['upload']['name']}... ",
            end="",
        )
        put_req = requests.put(
            upload_url, data=file_stream, headers={"content-type": mime}
        )
        print(" done")
        if not put_req.ok:
            raise Exception(f"Couldn't upload. Requests says: {put_req.reason}")
    started = datetime.datetime.now()
    while True:
        print(
            f"Upload of {filename} in state {upload_response['upload']['status']} "
            f"after " + str(datetime.datetime.now() - started)
        )
        if upload_response["upload"]["status"] == "FAILED":
            raise Exception(
                f"The upload failed processing. Device Farm says the reason is: \n"
                f"{+upload_response['upload']['message']}"
            )
        if upload_response["upload"]["status"] == "SUCCEEDED":
            break
        time.sleep(5)
        upload_response = client.get_upload(arn=upload_arn)
    print("")
    return upload_arn


our_upload_arn = upload_df_file(config["appFilePath"], "ANDROID_APP")
our_test_package_arn = upload_df_file(
    config["testPackage"], "APPIUM_PYTHON_TEST_PACKAGE"
)
print(our_upload_arn, our_test_package_arn)

response = client.schedule_run(
    projectArn=config["projectArn"],
    appArn=our_upload_arn,
    devicePoolArn=config["poolArn"],
    name=unique,
    test={
        "type": "APPIUM_PYTHON",
        "testSpecArn": config["testSpecArn"],
        "testPackageArn": our_test_package_arn,
    },
)
run_arn = response["run"]["arn"]
start_time = datetime.datetime.now()
print(f"Run {unique} is scheduled as arn {run_arn} ")

state = "UNKNOWN"
try:
    while True:
        response = client.get_run(arn=run_arn)
        state = response["run"]["status"]
        if state == "COMPLETED" or state == "ERRORED":
            break
        else:
            print(
                f" Run {unique} in state {state}, total "
                f"time {datetime.datetime.now() - start_time}"
            )
            time.sleep(10)
except:
    client.stop_run(arn=run_arn)
    exit(1)

print(f"Tests finished in state {state} after {datetime.datetime.now() - start_time}")
# Pull all the logs.
jobs_response = client.list_jobs(arn=run_arn)
# Save the output somewhere, using the unique value.
save_path = os.path.join(os.getcwd(), "results", unique)
os.mkdir(save_path)
# Save the last run information.
for job in jobs_response["jobs"]:
    job_name = job["name"]
    os.makedirs(os.path.join(save_path, job_name), exist_ok=True)
    # Get each suite within the job.
    suites = client.list_suites(arn=job["arn"])["suites"]
    for suite in suites:
        for test in client.list_tests(arn=suite["arn"])["tests"]:
            # Get the artifacts.
            for artifact_type in ["FILE", "SCREENSHOT", "LOG"]:
                artifacts = client.list_artifacts(type=artifact_type, arn=test["arn"])[
                    "artifacts"
                ]
                for artifact in artifacts:
                    # Replace `:` because it has a special meaning in Windows & macOS.
                    path_to = os.path.join(
                        save_path,
                        job_name,
                        suite["name"],
                        test["name"].replace(":", "_"),
                    )
                    os.makedirs(path_to, exist_ok=True)
                    filename = (
                        artifact["type"]
                        + "_"
                        + artifact["name"]
                        + "."
                        + artifact["extension"]
                    )
                    artifact_save_path = os.path.join(path_to, filename)
                    print(f"Downloading {artifact_save_path}")
                    with open(artifact_save_path, "wb") as fn:
                        with requests.get(
                            artifact["url"], allow_redirects=True
                        ) as request:
                            fn.write(request.content)
print("Finished")
```
+ 如需 API 詳細資訊，請參閱《適用於 Python (Boto3) 的AWS SDK API 參考》**中的下列主題。
  + [CreateUpload](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/CreateUpload)
  + [GetRun](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/GetRun)
  + [GetUpload](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/GetUpload)
  + [ListArtifacts](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/ListArtifacts)
  + [ListJobs](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/ListJobs)
  + [ListSuites](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/ListSuites)
  + [ListTests](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/ListTests)
  + [ScheduleRun](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/ScheduleRun)
  + [StopRun](https://docs.aws.amazon.com/goto/boto3/devicefarm-2015-06-23/StopRun)

------