문제

단위 테스트가 "완전히 훌륭함", "정말 멋지다", "모든 방식의 좋은 것"이라고 들었지만 내 파일의 70 % 이상이 데이터베이스 액세스 (일부 읽기 및 쓰기)와 관련되어 있습니다.이 파일에 대한 단위 테스트를 작성하는 방법을 모르겠습니다.

PHP와 Python을 사용하고 있지만 데이터베이스 액세스를 사용하는 대부분의 / 모든 언어에 적용되는 질문이라고 생각합니다.

도움이 되었습니까?

해결책

데이터베이스에 대한 호출을 조롱하는 것이 좋습니다. Mocks는 기본적으로 호출자가 사용할 수있는 동일한 속성, 메서드 등을 가지고 있다는 점에서 메서드를 호출하려는 개체와 유사한 개체입니다. 그러나 특정 메서드가 호출 될 때 수행하도록 프로그래밍 된 작업을 수행하는 대신이를 모두 건너 뛰고 결과를 반환합니다. 그 결과는 일반적으로 사용자가 미리 정의합니다.

모킹을 위해 개체를 설정하려면 다음 의사 코드에서와 같이 일종의 반전 제어 / 종속성 주입 패턴을 사용해야합니다. 라코 디스

이제 단위 테스트에서 FooDataProvider의 모의를 생성하여 실제로 데이터베이스에 접속하지 않고도 GetAllFoos 메서드를 호출 할 수 있습니다. 라코 디스

간단히 말하면 일반적인 조롱 시나리오입니다. 물론 실제 데이터베이스 호출도 단위 테스트를 원할 것입니다.이 경우 데이터베이스를 검색해야합니다.

다른 팁

이상적으로, 객체는 지속적으로 무지해야합니다. 예를 들어, 객체를 반환하는 요청을 할 "데이터 액세스 레이어"가 있어야합니다. 이렇게하면 해당 부분을 단위 테스트에서 제외하거나 격리 된 상태로 테스트 할 수 있습니다.

객체가 데이터 영역과 밀접하게 연결되어있는 경우 적절한 단위 테스트를 수행하기가 어렵습니다. 단위 테스트의 첫 번째 부분은 "단위"입니다. 모든 단위는 격리 된 상태에서 테스트 할 수 있어야합니다.

C # 프로젝트에서 완전히 분리 된 데이터 레이어와 함께 NHibernate를 사용합니다. 내 개체는 핵심 도메인 모델에 있으며 내 애플리케이션 계층에서 액세스됩니다. 애플리케이션 계층은 데이터 계층 및 도메인 모델 계층과 통신합니다.

애플리케이션 계층은 "비즈니스 계층"이라고도합니다.

PHP를 사용하는 경우 데이터 액세스 전용 을위한 특정 클래스 집합을 만듭니다. 객체가 어떻게 지속되는지 알지 못하도록하고 애플리케이션 클래스에서 두 개를 연결합니다.

또 다른 옵션은 조롱 / 스텁을 사용하는 것입니다.

데이터베이스 액세스로 개체를 단위 테스트하는 가장 쉬운 방법은 트랜잭션 범위를 사용하는 것입니다.

예 : 라코 디스

이것은 기본적으로 트랜잭션 롤백처럼 데이터베이스의 상태를 되돌 리므로 부작용없이 원하는만큼 테스트를 실행할 수 있습니다.우리는 대규모 프로젝트에서이 접근 방식을 성공적으로 사용했습니다.빌드를 실행하는 데 약간의 시간 (15 분)이 걸리지 만 1800 개의 단위 테스트를 수행하는 것은 끔찍하지 않습니다.또한 빌드 시간이 문제가되는 경우 빌드 프로세스를 여러 빌드로 변경할 수 있습니다. 하나는 src 빌드 용이고 다른 하나는 나중에 실행되어 단위 테스트, 코드 분석, 패키징 등을 처리합니다.

클래스를 단위 테스트하려면 데이터베이스 액세스를 모의해야합니다.결국 단위 테스트에서 데이터베이스를 테스트하고 싶지는 않습니다.그것은 통합 테스트가 될 것입니다.

호출을 요약 한 다음 예상 데이터를 반환하는 모의를 삽입합니다.클래스가 쿼리를 실행하는 것 이상을 수행하지 않는다면 테스트 할 가치가 없을 수도 있습니다 ...

많은 "비즈니스 로직"SQL 작업이 포함 된 중간 계층 프로세스를 단위 테스트하기 시작했을 때의 경험을 맛볼 수 있습니다.

처음에는 합리적인 데이터베이스 연결을 "슬롯 인"할 수있는 추상화 계층을 만들었습니다 (이 경우에는 단일 ODBC 유형 연결 만 지원함).

이 작업이 완료되면 코드에서 다음과 같은 작업을 수행 할 수있었습니다 (C ++로 작업하지만 아이디어를 얻을 수있을 것입니다).

GetDatabase (). ExecuteSQL ( "INSERT INTO foo (blah, blah)")

정상 런타임에서 GetDatabase ()는 ODBC를 통해 데이터베이스에 직접 모든 SQL (쿼리 포함)을 제공하는 개체를 반환합니다.

그런 다음 인 메모리 데이터베이스를 조사하기 시작했습니다. 먼 길에서 가장 좋은 것은 SQLite 인 것 같습니다. ( http://www.sqlite.org/index.html ). 설정 및 사용이 매우 간단하며, 수행 된 모든 테스트에 대해 생성 및 삭제 된 메모리 내 데이터베이스에 SQL을 전달하기 위해 GetDatabase () 하위 클래스 및 재정의를 허용했습니다.

아직 초기 단계에 있지만 지금까지는 괜찮아 보이지만 필요한 테이블을 만들고 테스트 데이터로 채워야합니다.하지만 작업 부하를 다소 줄였습니다. 여기에서 우리를 위해이 모든 일을 할 수있는 일반적인 도우미 함수 세트를 만듭니다.

전반적으로 TDD 프로세스에 큰 도움이되었습니다. 왜냐하면 특정 버그를 수정하기 위해 매우 무해한 것처럼 보이는 변경은 시스템의 다른 (탐지하기 어려운) 영역에 매우 이상한 영향을 미칠 수 있기 때문입니다. / databases.

분명히 우리의 경험은 C ++ 개발 환경을 중심으로 이루어졌지만 아마도 PHP / Python에서 비슷한 작업을 할 수있을 것이라고 확신합니다.

도움이 되었기를 바랍니다.

xUnit 테스트 패턴 책은 단위 테스트 코드를 처리하는 몇 가지 방법을 설명합니다.데이터베이스에 충돌합니다.나는 느리기 때문에 이것을하고 싶지 않다고 말하는 다른 사람들의 의견에 동의하지만 언젠가는해야합니다, IMO.더 높은 수준의 항목을 테스트하기 위해 db 연결을 조롱하는 것은 좋은 생각이지만이 책에서 실제 데이터베이스와 상호 작용하기 위해 수행 할 수있는 작업에 대한 제안을 확인하십시오.

사용 가능한 옵션 :

  • 단위 테스트를 시작하기 전에 데이터베이스를 지우는 스크립트를 작성한 다음 사전 정의 된 데이터 세트로 db를 채우고 테스트를 실행합니다. 또한 모든 테스트 전에 할 수 있습니다. 속도는 느리지 만 오류 발생 가능성은 적습니다.
  • 데이터베이스를 삽입합니다. (의사 자바의 예이지만 모든 OO 언어에 적용됨)

    class Database {
     public Result query(String query) {... real db here ...}
    }

    class MockDatabase extends Database { public Result query(String query) { return "mock result"; } }

    class ObjectThatUsesDB { public ObjectThatUsesDB(Database db) { this.database = db; } }

    이제 프로덕션에서는 일반 데이터베이스를 사용하고 모든 테스트에 대해 임시로 만들 수있는 모의 데이터베이스를 삽입합니다.

  • 대부분의 코드에서 DB를 전혀 사용하지 마십시오 (어쨌든 나쁜 습관입니다). 결과를 반환하는 대신 일반 개체를 반환하는 "데이터베이스"개체를 만들고 (즉, 튜플 User 대신 {name: "marcin", password: "blah"}를 반환합니다) 임시로 구성된 실제 개체로 모든 테스트를 작성하고 다음과 같은 하나의 큰 테스트를 작성합니다. 이 변환이 제대로 작동하는지 확인하는 데이터베이스에 의존합니다.

    물론 이러한 접근 방식은 상호 배타적이지 않으며 필요에 따라 혼합 및 일치시킬 수 있습니다.

저는 일반적으로 개체 (및 ORM (있는 경우)) 테스트와 db 테스트간에 테스트를 나누려고합니다.나는 데이터 액세스 호출을 모의하여 사물의 객체 측을 테스트하는 반면, 내 경험상 일반적으로 상당히 제한적인 db와의 객체 상호 작용을 테스트하여 사물의 db 측을 테스트합니다.

데이터 액세스 부분을 조롱하기 시작할 때까지 단위 테스트를 작성하는 데 좌절 했었기 때문에 테스트 DB를 만들거나 테스트 데이터를 즉시 생성 할 필요가 없었습니다.데이터를 조롱함으로써 런타임에 모든 데이터를 생성 할 수 있으며 객체가 알려진 입력으로 제대로 작동하는지 확인할 수 있습니다.

나는 PHP에서 이것을 한 적이없고 파이썬을 사용한 적이 없지만, 당신이하고 싶은 것은 데이터베이스에 대한 호출을 모의하는 것입니다.이를 위해 타사 도구 또는 사용자가 직접 관리하는지 여부에 관계없이 일부 IoC 를 구현할 수 있습니다.가짜 호출의 결과를 제어 할 데이터베이스 호출자의 모의 버전을 구현할 수 있습니다.

간단한 형태의 IoC는 인터페이스 코딩만으로 수행 할 수 있습니다.이것은 당신의 코드에서 어떤 종류의 객체 지향이 필요하기 때문에 당신이하는 일에 적용되지 않을 수도 있습니다. (필자는 PHP와 Python에 대해 언급하기 만하면됩니다)

도움이 되었기를 바랍니다. 지금 검색 할 용어가 없다면

첫 번째 게시물에 동의합니다. 데이터베이스 액세스는 인터페이스를 구현하는 DAO 계층으로 분리되어야합니다.그런 다음 DAO 계층의 스텁 구현에 대해 논리를 테스트 할 수 있습니다.

모의 프레임 워크 를 사용하여 데이터베이스 엔진을 추상화 할 수 있습니다.PHP / Python이 몇 가지 있는지 모르겠지만 형식화 된 언어 (C #, Java 등)에는 선택의 폭이 넓습니다.

일부 디자인은 이전 게시물에서 언급 한 다른 디자인보다 단위 테스트가 더 쉽기 때문에 데이터베이스 액세스 코드를 디자인 한 방법에 따라 다릅니다.

프로젝트가 전체적으로 응집력이 높고 결합이 느슨하다면 데이터베이스 액세스 단위 테스트가 쉽습니다. 이렇게하면 한 번에 모든 것을 테스트 할 필요없이 각 특정 클래스가 수행하는 작업 만 테스트 할 수 있습니다.

예를 들어 사용자 인터페이스 클래스를 단위 테스트하는 경우 작성하는 테스트는 UI 내부의 논리가 예상대로 작동하는지 확인해야하며 해당 기능 뒤에있는 비즈니스 논리 또는 데이터베이스 작업이 아닌지 확인해야합니다.

실제 데이터베이스 액세스를 단위 테스트하려는 경우 네트워크 스택과 데이터베이스 서버에 의존하기 때문에 실제로 더 많은 통합 테스트를 거치게되지만 SQL 코드가 원하는 작업을 수행하는지 확인할 수 있습니다. 요청했습니다.

개인적으로 유닛 테스트의 숨겨진 힘은 애플리케이션이없는 것보다 훨씬 더 나은 방식으로 애플리케이션을 설계해야한다는 것입니다. "이 기능은 모든 것을해야한다"는 사고 방식에서 벗어나는 데 정말 도움이 되었기 때문입니다.

죄송합니다. PHP / Python에 대한 특정 코드 예제는 없지만 .NET 예제를 보려면 게시물 은이 동일한 테스트를 수행하는 데 사용한 기술을 설명합니다.

단위 테스트를위한 테스트 데이터 설정은 어려울 수 있습니다.

자바의 경우 단위 테스트에 Spring API를 사용하면 단위 수준에서 트랜잭션을 제어 할 수 있습니다.즉, 데이터베이스 업데이트 / 삽입 / 삭제 및 변경 사항을 롤백하는 단위 테스트를 실행할 수 있습니다.실행이 끝나면 실행을 시작하기 전의 모든 것을 데이터베이스에 그대로 둡니다.나에게 그것은 얻을 수있는 한 좋은 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top