복잡한 API (예 : Amazon S3)에 의존하는 코드를 테스트하는 방법은 무엇입니까? S3. 나는 그 물체의 내부에 대해 전혀

Amazon S3에 문서를 업로드하는 방법을 테스트하는 데 어려움을 겪고 있지만이 질문은 사소한 API / 외부 의존성에 적용된다고 생각합니다. 나는 세 가지 잠재적 인 해결책을 생각해 냈지만 만족스러운 것은 없습니다.

  1. 코드를 실행하고 실제로 문서를 업로드하고 업로드 된 AWS API를 확인한 후 테스트가 끝나면 삭제하십시오. 이렇게하면 테스트 속도가 매우 느려지고 테스트를 실행할 때마다 비용이 발생하며 항상 같은 결과를 반환하지 않습니다.

  2. 모의 S3. 나는 그 물체의 내부에 대해 전혀 모르고 너무 복잡하기 때문에 잘못 느낍니다.

  3. MyObject.upload ()가 올바른 인수로 호출되었는지 확인하고 S3 객체를 올바르게 사용하고 있다고 신뢰하십시오. 테스트만으로 S3 API를 올바르게 사용했는지 확실하게 알 수있는 방법이 없기 때문에 문제가됩니다.

아마존이 자체 SDK를 테스트하는 방법을 확인하고 모든 것을 조롱합니다. 그들은 조롱을하는 200 줄 도우미가 있습니다. 나는 똑같이하는 것이 실용적이라고 생각하지 않습니다.

이 문제를 어떻게 해결합니까?



답변

여기서 살펴 봐야 할 두 가지 문제가 있습니다.

첫 번째는 단위 테스트 관점에서 모든 테스트를보고있는 것 같습니다. 단위 테스트는 매우 중요하지만 유일한 테스트는 아닙니다. 테스트는 실제로 매우 빠른 단위 테스트 에서 덜 빠른 통합 테스트 , 더 느린 수락 테스트에 이르기까지 여러 계층으로 나눌 수 있습니다 . ( 기능 테스트 와 같이 더 많은 레이어가 나올 수 있습니다 .)

두 번째는 비즈니스 로직과 타사 코드 호출을 혼합하여 테스트 문제를 일으키고 코드를 더 취약하게 만드는 것입니다.

단위 테스트는 빠르며 자주 실행해야합니다. 종속성을 모의하면 이러한 테스트를 빠르게 실행하는 데 도움이되지만 종속성이 변경되고 모의가 변경되지 않으면 적용 범위에 문제가 발생할 수 있습니다. 테스트가 여전히 녹색으로 실행되는 동안 코드가 손상 될 수 있습니다. 일부 조롱 라이브러리는 종속성의 인터페이스가 변경되면 경고하지만 다른 라이브러리는 그렇지 않습니다.

반면에 통합 테스트는 타사 라이브러리를 포함하여 구성 요소 간의 상호 작용을 테스트하도록 설계되었습니다. 실제 객체가 상호 작용하는 방식을보고 싶기 때문에이 수준의 테스트에서는 Mocks를 사용해서는 안됩니다. 실제 객체를 사용하기 때문에 이러한 테스트 속도가 느려지고 단위 테스트만큼 자주 실행하지는 않습니다.

승인 테스트는 소프트웨어의 요구 사항이 충족되는지 테스트하면서 훨씬 더 높은 수준을 확인합니다. 이러한 테스트는 배포 될 전체 시스템 전체에 대해 실행됩니다. 다시 한 번 조롱을 사용해서는 안됩니다.

사람들이 모의와 관련하여 귀중한 것으로 알고있는 지침 중 하나는 소유하지 않은 유형을 조롱하는 것 입니다. Amazon은 S3에 대한 API를 소유하므로 그 아래에서 변경되지 않도록 할 수 있습니다. 반면에, 당신은 이러한 확신을 가지고 있지 않습니다. 따라서 테스트에서 S3 API를 모의하면 코드가 변경되고 중단 될 수 있지만 테스트는 모두 녹색으로 표시됩니다. 그렇다면 타사 라이브러리를 사용하는 코드를 어떻게 단위 테스트합니까?

글쎄, 우리는하지 않습니다. 지침을 준수하면 소유하지 않은 물건을 조롱 할 수 없습니다. 그러나 … 직접 의존성을 소유하고 있다면 그것을 조롱 할 수 있습니다. 그러나 어떻게? 우리는 S3 API를위한 자체 래퍼를 만듭니다. S3 API와 비슷하게 보이게하거나 필요에 더 잘 맞도록 (바람직하게) 만들 수 있습니다. 우리는 심지어 조금 더 추상적하는 말을 할 수 PersistenceService보다는를 AmazonS3Bucket. and와 PersistenceService같은 메소드가있는 인터페이스 가 될 것입니다. 이제 호출 코드에서 캡슐화 하여 S3 API 주변 (예 :)을 구현할 수 있습니다 .#save(Thing)#fetch(ThingId)PersistenceServiceS3PersistenceService

이제 S3 API를 호출하는 코드입니다. 이러한 호출을 PersistenceService객체 에 대한 호출로 교체해야 합니다. 의존성 주입 을 사용 PersistenceService하여 객체 에 전달 합니다. 을 요구 하지 말고을 요청하는 것이 중요 S3PersistenceService합니다 PersistenceService. 이를 통해 테스트 중에 구현을 교체 할 수 있습니다.

S3 API를 사용하는 데 사용하는 모든 코드는 바로 지금 우리를 사용하여 PersistenceService, 우리는 S3PersistenceService이제 S3 API에 대한 모든 호출합니다. 테스트에서 우리는 PersistenceService그것을 소유하고 있기 때문에 mock out 할 수 있고 mock을 사용하여 코드가 올바르게 호출되는지 확인할 수 있습니다. 그러나 이제는 테스트하는 방법이 남습니다 S3PersistenceService. 이전과 같은 문제가 있습니다. 외부 서비스를 호출하지 않으면 단위 테스트를 수행 할 수 없습니다. 우리는 그것을 단위 테스트하지 않습니다. 우리 는 S3 API 의존성을 모방 할 수 있지만, 그에 대한 확신은 거의 없습니다. 대신, 우리는 통합 테스트라는 높은 수준에서 테스트해야합니다.

코드의 일부를 단위 테스트하지 말고 우리가 달성 한 것을 살펴 보자. 우리는 단위 테스트를 할 수 없었던 곳곳에 많은 코드가 있었는데, 이제는를 통해 단위 테스트를 할 수 있습니다 PersistenceService. 우리는 타사 라이브러리 엉망이 단일 구현 클래스에 국한되어 있습니다. 해당 클래스는 API를 사용하는 데 필요한 기능을 제공해야하지만 외부 비즈니스 로직이 첨부되어 있지 않습니다. 따라서 일단 작성되면 매우 안정적이어야하며 크게 바뀌지 않아야합니다. 코드가 안정적이기 때문에 자주 실행하지 않는 느린 테스트에 의존 할 수 있습니다.

다음 단계는에 대한 통합 테스트를 작성하는 것입니다 S3PersistenceService. 빠른 단위 테스트와 별도로 실행할 수 있도록 이름 또는 폴더로 분리해야합니다. 통합 테스트는 코드가 충분한 정보를 제공하는 경우 단위 테스트와 동일한 테스트 프레임 워크를 사용할 수 있으므로 새로운 도구를 배울 필요가 없습니다. 통합 테스트에 대한 실제 코드는 옵션 1에 대해 작성하는 것입니다.


답변

둘 다해야합니다.

실행, 업로드 및 삭제는 통합 테스트입니다. 외부 시스템과 인터페이스하므로 느리게 실행될 것으로 예상 할 수 있습니다. 로컬에서 수행하는 모든 단일 빌드의 일부는 아니지만 CI 빌드 또는 야간 빌드의 일부 여야합니다. 이는 해당 테스트의 속도 저하를 상쇄하고 자동 테스트의 가치를 제공합니다.

또한 더 빨리 실행되는 단위 테스트가 필요합니다. 일반적으로 외부 시스템에 너무 의존하지 않는 것이 현명하기 때문에 (구현을 교체하거나 전환 할 수 있음) 코딩 할 수있는 S3를 통해 간단한 인터페이스를 작성해야합니다. 단위 테스트에서 해당 인터페이스를 조롱하여 단위 테스트를 빠르게 실행할 수 있습니다.

첫 번째 테스트는 코드가 실제로 S3에서 작동하는지 확인하고 두 번째 테스트는 코드가 S3과 통신하는 코드를 올바르게 호출하는지 테스트합니다.


답변

API 사용의 복잡성에 달려 있다고 말하고 싶습니다 .

  1. 실제로 S3 API를 실제로 호출하고 테스트가 끝까지 끝났음을 확인하는 테스트를 수행해야합니다.

  2. 또한 실제로 API를 호출하지 않는 추가 테스트를 수행해야하므로 API를 항상 호출하지 않고도 자체 소프트웨어를 적절히 테스트 할 수 있습니다.

남아있는 질문은 : 당신은 API를 조롱해야합니까?

그리고 나는 그것이 당신이 얼마나 많이하는지에 달려 있다고 생각합니다. 하나 또는 두 개의 간단한 작업 만 수행하는 경우 모형의 모든 문제를 해결해야한다고 생각하지 않습니다. 기능 사용을 확인하고 실시간 테스트를 수행하는 것으로 만족합니다.

그러나 결과가 영향을 줄 수있는 다양한 시나리오와 변수로 인해 사용이 더 복잡한 경우보다 철저한 테스트를 수행하기 위해이를 조롱해야 할 수도 있습니다.


답변

이전 답변에 추가하여 주요 질문은 테스트를 위해 S3 API를 조롱할지 여부와 방법입니다.

개별 S3 응답을 수동으로 조롱하는 대신 매우 정교한 기존 조롱 프레임 워크를 활용할 수 있습니다. 예를 들어 moto 는 실제 S3 API와 매우 유사한 기능을 제공합니다.

기존 도구를 결합하고 통합 테스트를 용이하게하는 완전한 기능을 갖춘 로컬 클라우드 환경 (S3 포함)을 제공하는 프레임 워크 인 LocalStack을 살펴볼 수도 있습니다 .

이러한 도구 중 일부는 다른 언어 (Python)로 작성되었지만 Java / JUnit과 같은 테스트에서 외부 프로세스로 테스트 환경을 쉽게 시작할 수 있습니다.