코드 작성 후 단위 테스트를 사용하면 코드의 품질을 확인할 수 있으며 개발을 진행하면서 개발 프로세스를 개선하는 데도 단위 테스트를 사용할 수 있습니다. 애플리케이션 개발을 마친 후에 테스트를 작성하는 대신 개발을 진행하면서 테스트를 작성하는 것이 좋습니다. 그러면 작고 유지관리 및 재사용이 가능한 코드 단위를 설계하는 데 도움이 됩니다. 또한 코드를 완벽하고 신속하게 테스트하기도 더 쉽습니다.
로컬 단위 테스트를 수행할 때는 원격 구성요소를 사용하지 않고 자체 개발 환경 내에서 테스트를 실행합니다. App Engine에서는 데이터 저장소와 기타 App Engine 서비스의 로컬 구현을 사용하는 테스트 유틸리티를 제공합니다. 따라서 코드를 App Engine에 배포하지 않고 서비스 스텁을 사용하여 코드에서 이러한 서비스를 사용하는 방식을 로컬에서 테스트해 볼 수 있습니다.
서비스 스텁은 서비스의 동작을 시뮬레이션하는 수단입니다. 예를 들어 Datastore 및 Memcache 테스트 작성에 표시된 데이터 저장소 서비스 스텁을 사용하면 실제 데이터 저장소에 어떠한 요청도 하지 않고 데이터 저장소 코드를 테스트할 수 있습니다. 데이터 저장소 단위 테스트 중에 저장된 모든 항목은 데이터 저장소가 아니라 메모리에 보관되었다가 테스트 실행 후에 삭제됩니다. 데이터 저장소 자체에 어떠한 종속성도 없이 소규모 테스트를 빠르게 실행할 수 있습니다.
이 문서에서는 몇 개의 로컬 App Engine 서비스에 대한 단위 테스트를 작성하는 방법을 설명하고 테스트 프레임워크 설정에 대한 몇 가지 정보를 제공합니다.
Python 2 테스트 유틸리티 소개
testbed
라는 App Engine Python 모듈은 단위 테스트에 서비스 스텁을 사용할 수 있도록 합니다.
서비스 스텁은 다음 서비스에 사용할 수 있습니다.
- 앱 ID
init_app_identity_stub
- Blobstore(
init_blobstore_stub
사용) - Capability(
init_capability_stub
사용) - Datastore(
init_datastore_v3_stub
사용) - Files(
init_files_stub
사용) - Images(dev_appserver전용,
init_images_stub
사용) - LogService(
init_logservice_stub
사용) - Mail(
init_mail_stub
사용) - Memcache(
init_memcache_stub
사용) - 태스크 큐(
init_taskqueue_stub
사용) - URL Fetch(
init_urlfetch_stub
사용) - 사용자 서비스(
init_user_stub
사용)
모든 스텁을 동시에 초기화하려면 init_all_stubs
를 사용합니다.
Datastore 및 memcache 테스트 작성
이 섹션에서는 Datastore 및 Memcache 서비스의 사용을 테스트하는 코드의 작성 방법을 예시로 보여줍니다.
App Engine 라이브러리, yaml
(App Engine SDK에 포함), 애플리케이션 루트, 애플리케이션 코드에 필요한 라이브러리 경로의 기타 모든 수정사항(예: 있는 경우 로컬 ./lib
디렉터리)을 비롯하여 Python 로드 경로에 있는 적절한 라이브러리를 테스트 실행기에 제공해야 합니다. 예를 들면 다음과 같습니다.
import sys
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine')
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine/lib/yaml/lib')
sys.path.insert(1, 'myapp/lib')
Python unittest
모듈과 테스트할 서비스에 관련된 App Engine 모듈을 가져옵니다. 이 경우에는 Datastore와 Memcache를 모두 사용하는 memcache
와 ndb
가 해당됩니다. 또한 testbed
모듈도 가져옵니다.
그런 다음 TestModel
클래스를 만듭니다. 이 예시에서는 함수를 통해 항목이 Memcache에 저장되었는지 여부를 확인합니다. 항목이 없으면 Datastore의 항목을 확인합니다. ndb
가 커튼 뒤에서 자체적으로 Memcache를 사용하지만 여전히 테스트에서는 OK 패턴이므로 실제 상황에서는 종종 중복이 될 수 있습니다.
다음으로는 테스트 사례를 만듭니다. 어떤 서비스를 테스트하든 테스트 사례를 통해 Testbed
인스턴스를 만들어 활성화해야 합니다. 또한 테스트 사례를 통해 관련 서비스 스텁을 초기화해야 합니다. 이 예시에서는 init_datastore_v3_stub
및 init_memcache_stub
를 사용하여 관련 서비스 스텁을 초기화합니다. 다른 App Engine 서비스 스텁을 초기화하는 메서드는 Python 테스트 유틸리티 소개에 나열되어 있습니다.
인수가 없는 init_datastore_v3_stub()
메서드는 처음에 비어 있는 메모리 내 Datastore를 사용합니다. 기존 Datastore 항목을 테스트하려면 init_datastore_v3_stub()
에 해당 경로 이름을 인수로 포함합니다.
setUp()
외에도 testbed를 비활성화하는 tearDown()
메서드를 포함합니다. 이 메서드는 테스트 간에 간섭이 발생하지 않도록 원래 스텁을 복원합니다.
다음으로는 테스트를 구현합니다.
이제 TestModel
을 사용하여 실제 서비스 대신 Datastore 또는 Memcache 서비스 스텁을 사용하는 테스트를 작성할 수 있습니다.
예를 들어 아래 표시된 메서드는 두 개의 항목을 만듭니다. 첫 번째 항목은 number
속성에 기본값(42)을 사용하고 두 번째 항목은 number
에 기본값이 아닌 값(17)을 사용합니다. 그런 다음 이 메서드는 number
에 기본값을 사용하는 항목만을 대상으로 TestModel
항목에 대한 쿼리를 빌드합니다.
일치하는 모든 항목을 검색한 후 이 메서드는 정확히 하나의 항목이 발견되었고 해당 항목의 number
속성 값이 기본값인지 테스트합니다.
또 다른 예시로 다음 메서드는 항목을 만든 후 위에서 만든 GetEntityViaMemcache()
함수를 사용하여 해당 항목을 검색합니다. 그런 다음 이 메서드는 항목이 반환되었고 해당 항목의 number
값이 이전에 만든 항목의 값과 동일한지 테스트합니다.
마지막으로 unittest.main()
을 호출합니다.
테스트를 실행하려면 테스트 실행을 참조하세요.
Cloud Datastore 테스트 작성
앱이 Cloud Datastore를 사용하는 경우 eventual consistency에 직면하여 애플리케이션의 동작을 확인하는 테스트를 작성할 수 있습니다.
db.testbed
는 이를 쉽게 하는 옵션을 제공합니다.
PseudoRandomHRConsistencyPolicy
클래스를 사용하면 각각의 전역(비상위) 쿼리 전에 쓰기가 적용될 가능성을 제어할 수 있습니다. 이 확률을 0%로 설정하면 Datastore 스텁이 최대한의 eventual consistency 상태에서 작동하게 됩니다. 최대한의 최종 일관성 상태에서는 쓰기가 커밋되지만 항상 적용에 실패하므로 전역(비상위) 쿼리가 일관되게 변경사항을 확인하지 못하게 됩니다. 물론 이것이 프로덕션 환경에서 실행 시 애플리케이션에서 실제로 확인되는 eventual consistency 수준을 나타내지는 않지만, 테스트 목적으로는 로컬 Datastore를 매번 이런 식으로 작동하도록 구성하는 것이 매우 유용합니다. 0이 아닌 확률을 사용하는 경우 PseudoRandomHRConsistencyPolicy
는 일관성과 관련한 일련의 사항을 확정적으로 결정하므로 테스트 결과가 일관됩니다.
Testing API는 eventual consistency에 직면하여 애플리케이션이 제대로 작동하는지 확인하는 데 유용하지만, 로컬 고성능 복제 읽기 일관성 모델은 프로덕션 고성능 복제 읽기 일관성 모델의 정확한 복제본이 아니라 근사치임에 유의해야 합니다. 로컬 환경에서 적용되지 않은 쓰기가 있는 항목 그룹에 속하는 Entity
에 대해 get()
을 수행하면 후속 전역 쿼리에서는 적용되지 않은 쓰기의 결과가 항상 표시됩니다. 이는 프로덕션 환경에서는 해당되지 않습니다.
메일 테스트 작성
mail 서비스 스텁을 사용하여 mail 서비스를 테스트할 수 있습니다. testbed에서 지원되는 다른 서비스와 마찬가지로 먼저 스텁을 초기화한 다음 Mail API를 사용하는 코드를 호출하고 마지막으로 올바른 메시지가 전송되었는지 테스트합니다.
태스크 큐 테스트 작성
taskqueue 스텁을 사용하여 taskqueue 서비스를 사용하는 테스트를 작성할 수 있습니다. testbed에서 지원되는 다른 서비스와 마찬가지로 먼저 스텁을 초기화한 다음 Task Queue API를 사용하는 코드를 호출하고 마지막으로 태스크가 큐에 올바르게 추가되었는지 테스트합니다.
queue.yaml
구성 파일 설정
기본이 아닌 큐와 상호작용하는 코드에 대해 테스트를 실행하려면 애플리케이션에서 사용할 queue.yaml
파일을 만들어 지정해야 합니다.
아래에 예시 queue.yaml
이 나와 있습니다.
사용 가능한 queue.yaml 옵션에 대한 자세한 내용은 태스크 큐 구성을 참조하세요.
queue.yaml
의 위치는 스텁을 초기화할 때 지정합니다.
self.testbed.init_taskqueue_stub(root_path='.')
이 샘플에서 queue.yaml
은 테스트와 동일한 디렉터리에 있습니다. 이 파일이 다른 폴더에 있다면 root_path
에 해당 경로를 지정해야 합니다.
태스크 필터링
태스크 큐 스텁의 get_filtered_tasks
를 사용하면 큐에 추가된 태스크를 필터링할 수 있습니다.
이렇게 하면 여러 태스크를 큐에 추가하는 코드를 확인하기 위한 테스트를 보다 쉽게 작성할 수 있습니다.
지연된 태스크 테스트 작성
애플리케이션 코드가 지연된 라이브러리를 사용하는 경우 taskqueue 스텁과 deferred
를 사용하여 지연된 함수가 올바르게 큐에 추가되고 실행되었는지 확인할 수 있습니다.
기본 환경 변수 변경
App Engine 서비스에는 종종 환경 변수가 필요합니다. testbed.Testbed
클래스의 activate()
메서드는 환경 변수에 기본값을 사용하지만, 사용자가 testbed.Testbed
클래스의 setup_env
메서드를 사용하여 테스트 요구사항에 따라 커스텀 값을 설정할 수도 있습니다.
예를 들어 여러 항목을 Datastore에 저장하는 테스트가 있으며 해당 항목들이 모두 동일한 애플리케이션 ID에 연결되어 있다고 가정해 보겠습니다. 이제 동일한 테스트를 다시 실행하되 저장된 항목에 연결된 애플리케이션 ID와는 다른 애플리케이션 ID를 사용하려고 합니다. 이렇게 하려면 새 값을 self.setup_env()
에 app_id
로 전달합니다.
예를 들면 다음과 같습니다.
로그인 시뮬레이션
setup_env
를 자주 사용하는 또 다른 경우는 관리자 권한으로 로그인하거나 관리자 권한 없이 로그인하는 사용자를 시뮬레이션하여 핸들러가 각각의 경우에 제대로 작동하는지 확인하는 경우입니다.
이제 테스트 메서드가 self.loginUser('', '')
, self.loginUser('test@example.com', '123')
, self.loginUser('test@example.com',
'123', is_admin=True)
를 호출하여 각각 로그인하는 사용자가 없는 경우, 관리자가 아닌 사용자가 로그인하는 경우, 관리자인 사용자가 로그인하는 경우를 시뮬레이션할 수 있습니다.
테스트 프레임워크 설정
SDK의 테스트 유틸리티는 특정 프레임워크로 한정되어 있지 않습니다. 사용 가능한 모든 App Engine 테스트 실행기(예: nose-gae, ferrisnose)로 단위 테스트를 실행할 수 있습니다. 직접 테스트 실행기를 작성하거나, 아래에 표시된 테스트 실행기를 사용할 수도 있습니다.
다음 스크립트에서는 Python의 unittest 모듈을 사용합니다.
스크립트 이름은 원하는 대로 지정할 수 있습니다. 스크립트를 실행할 때 Google Cloud CLI 또는 Google App Engine SDK의 설치 경로와 테스트 모듈의 경로를 제공하세요. 이 스크립트는 제공된 경로에서 모든 테스트를 검색하고 결과를 표준 오류 스트림에 출력합니다. 테스트 파일은 이름 앞에 test
프리픽스를 추가하는 규칙을 따릅니다.
테스트 실행
테스트 프레임워크 설정에 자세히 설명된 runner.py
스크립트를 실행하기만 하면 이러한 테스트를 실행할 수 있습니다.
python runner.py <path-to-appengine-or-gcloud-SDK> .