단위 테스트 및 데이터베이스 : 실제로 데이터베이스에 어느 시점에 연결합니까?


36

데이터베이스에 연결하는 테스트 클래스 (예 : "서비스 테스트 클래스 연결 ...""단위 테스트-데이터베이스 커플 링 앱") 에 대한 질문에 대한 답변이 있습니다 .

간단히 말해 데이터베이스에 연결해야하는 클래스 A가 있다고 가정합니다. A를 실제로 연결하는 대신 A에 연결하는 데 사용할 수있는 인터페이스를 A에 제공합니다. 테스트를 위해 연결하지 않고도 몇 가지 사항 으로이 인터페이스를 구현합니다. 클래스 B가 A를 인스턴스화하면 "실제"데이터베이스 연결을 A로 전달해야하지만 B는 데이터베이스 연결을 엽니 다. 즉, B를 테스트한다는 것은 B에 연결을 주입한다는 의미입니다. 그러나 B는 클래스 C 등에서 인스턴스화됩니다.

어느 시점에서 "데이터베이스에서 데이터를 가져 와서이 코드에 대한 단위 테스트를 작성하지 않겠다"고 말해야합니까?

다시 말해 : 어떤 클래스의 코드 어딘가에 전화 하거나 비슷한 것을 해야합니다sqlDB.connect() . 이 수업을 어떻게 테스트합니까?

그리고 GUI 나 파일 시스템을 다루어야하는 코드와 동일합니까?


Unit-Test를하고 싶습니다. 다른 종류의 테스트는 내 질문과 관련이 없습니다. 나는 한 클래스 만 시험한다는 것을 알고 있습니다 (Kilian도 동의합니다). 이제 일부 클래스는 DB에 연결해야합니다. 이 클래스를 테스트하고 "어떻게해야합니까?"라고 물으면 많은 사람들이 "Use Dependency Injection!"이라고 말합니다. 그러나 그것은 문제를 다른 클래스로만 옮기는 것입니까? 그래서 실제로 연결을 설정하는 클래스를 어떻게 테스트합니까?

보너스 질문 : 여기에있는 일부 답변은 "모의 객체 사용!"으로 요약됩니다. 그게 무슨 뜻이야? 테스트 대상 클래스가 의존하는 클래스를 조롱합니다. 이제 테스트 대상 클래스를 조롱하고 실제로 모의 테스트를 수행해야합니까 (템플릿 메소드 사용에 대한 아이디어에 가깝습니다. 아래 참조)?


테스트중인 데이터베이스 연결입니까? 메모리 데이터베이스에 임시 (예 : derby )를 작성할 수 있습니까?

@MichaelT 여전히 메모리 DB의 임시 데이터베이스를 실제 데이터베이스로 바꿔야합니다. 어디? 언제? 단위 테스트는 어떻게됩니까? 아니면이 코드를 단위 테스트하지 않는 것이 좋습니까?
TobiMcNamobi

3
데이터베이스에 대해 "단위 테스트"할 것은 없습니다. 그것은 다른 사람들에 의해 유지 관리되며, 버그가 있으면 직접 수정하지 말고 수정해야합니다. 실제 클래스 사용과 테스트 중에 사용하는 것 사이에 달라야하는 유일한 것은 데이터베이스 연결의 매개 변수 여야합니다. 속성 파일 읽기 코드 또는 Spring 주입 메커니즘 또는 앱을 함께 짜기 위해 사용하는 것이 손상되었을 가능성은 없습니다 (그렇다면 직접 수정할 수는 없습니다)-허용되는 것으로 간주합니다 이 배관 기능을 테스트하지 마십시오.
Kilian Foth

2
@KilianFoth는 전적으로 업무 환경 및 직원 역할과 관련이 있습니다. 그것은 실제로 질문과 관련이 없습니다. 데이터베이스를 담당하는 사람이 없으면 어떻게됩니까?
Reactgular

일부 모의 프레임 워크를 사용하면 모의 객체를 개인 및 정적 멤버에 이르기까지 거의 모든 것에 주입 할 수 있습니다. 이것은 모의 DB 연결과 같은 것들로 테스트하는 것이 훨씬 쉬워집니다. Mockito + Powermock은 요즘 나에게 도움이되는 것입니다 (Java입니다, 작업중 인 작업이 확실하지 않습니다).
FrustratedWithFormsDesigner

답변:


20

단위 테스트의 요점은 하나의 클래스 를 테스트하는 것입니다 (실제로 하나의 메소드를 테스트해야합니다 ).

A, 클래스를 테스트 할 때 테스트 데이터베이스 (자체 작성 또는 초고속 인 메모리 데이터베이스)를 테스트 데이터베이스에 삽입합니다.

그러나 B의 클라이언트 인 class를 테스트하는 경우 A일반적으로 A실제 A객체를 사용하지 않고 데이터를 사용하지 않고 기본적으로 사전 프로그래밍 된 방식으로 작업을 수행하는 다른 객체로 전체 객체 를 조롱합니다. base ( A전체 데이터베이스 연결을 호출자에게 다시 전달 하지 않는 한 그렇게 생각하지 않습니다.) 마찬가지로, C의 클라이언트 인 class 에 대한 단위 테스트를 작성할 때 B의 역할을하는 무언가를 조롱하고 완전히 B잊어 A버리게됩니다.

그렇게하지 않으면 더 이상 단위 테스트가 아니라 시스템 또는 통합 테스트입니다. 그것들은 매우 중요하지만 완전히 다른 물고기 주전자입니다. 우선, 그들은 일반적으로 설정하고 실행하는 데 더 많은 노력을 기울이며 체크인 등의 전제 조건으로 전달하도록 요구하는 것은 불가능합니다.


10

데이터베이스 연결에 대해 단위 테스트를 수행하는 것은 완전히 정상이며 일반적인 관행입니다. 시스템의 purist모든 것이 의존성 주입 가능한 접근 방식 을 만드는 것은 불가능합니다 .

여기서 핵심은 임시 또는 테스트 전용 데이터베이스에 대해 테스트하고 해당 테스트 데이터베이스를 빌드하기위한 가장 가벼운 시작 프로세스를 갖는 것입니다.

CakePHP의 단위 테스트에는이라고하는 것이 fixtures있습니다. 픽스처는 단위 테스트를 위해 즉석에서 생성 된 임시 데이터베이스 테이블입니다. 조명기는 그것들을 생성하기위한 편리한 방법을 가지고 있습니다. 테스트 데이터베이스 내의 프로덕션 데이터베이스에서 스키마를 다시 작성하거나 간단한 표기법을 사용하여 스키마를 정의 할 수 있습니다.

이것으로 성공의 비결은 비즈니스 데이터베이스를 구현하는 것이 아니라 테스트하는 코드의 측면에만 집중하는 것입니다. 데이터 모델이 게시 된 문서 만 읽는지 확인하는 단위 테스트가있는 경우 해당 테스트의 테이블 스키마에는 해당 코드에 필요한 필드 만 있어야합니다. 해당 코드를 테스트하기 위해 전체 컨텐츠 관리 데이터베이스를 다시 구현할 필요는 없습니다.

일부 추가 참조.

http://en.wikipedia.org/wiki/Test_fixture

http://phpunit.de/manual/3.7/en/database.html

http://book.cakephp.org/2.0/en/development/testing.html#fixtures


28
동의하지 않습니다. 데이터베이스 연결이 필요한 테스트는 본질적으로 테스트에 부작용이 있기 때문에 단위 테스트가 아닙니다. 그렇다고 자동화 된 테스트를 작성할 수 없다는 의미는 아니지만 통합 테스트라는 정의에 따르면 코드베이스를 넘어서 시스템 영역을 실행합니다.
KeithS

5
나를 순수 주의자로 불러라. 그러나 나는 단위 테스트가 테스트 런타임 환경의 "샌드 박스"를 떠나는 어떠한 행동도 수행해서는 안된다는 교리를 붙잡고있다. 데이터베이스, 파일 시스템, 네트워크 소켓 등을 건드리지 않아야합니다. 이것은 여러 가지 이유에 의해 외부 상태에 대한 테스트의 의존성이 아닙니다. 다른 하나는 성능입니다. 단위 테스트 스위트는 빠르게 실행되어야하며 이러한 외부 데이터 저장소와 인터페이스하면 테스트 속도가 느려집니다. 내 개발에서는 부분 모의를 사용하여 리포지토리와 같은 것을 테스트하고 샌드 박스에 "가장자리"를 정의하는 것이 편안합니다.
KeithS

2
@gbjbaanb-처음에는 괜찮아 보이지만 내 경험상 그것은 매우 위험합니다. 최고의 아키텍처 테스트 스위트 및 프레임 워크에서도이 트랜잭션을 롤백하는 코드가 실행되지 않을 수 있습니다. 테스트 러너가 충돌하거나 테스트 내부에서 중단되거나 테스트에서 SOE 또는 OOME이 발생하는 경우 가장 좋은 경우는 연결이 끊길 때까지 사용자가 터치 한 테이블을 잠그는 연결 및 트랜잭션이 DB에 걸려있는 것입니다. SQLite를 테스트 DB로 사용하는 것과 같은 문제를 방지하는 방법 에는 실제 DB를 실제로 사용 하지 않는 등의 단점이 있습니다.
KeithS

5
@KeithS 의미론에 대해 토론하고 있다고 생각합니다. 단위 테스트의 정의 또는 통합 테스트의 정의가 아닙니다. 조명기를 사용하여 데이터베이스 연결에 따라 코드를 테스트합니다. 그것이 통합 테스트라면 괜찮습니다. 시험 합격을 알아야합니다. 종속성, 성능 또는 위험에 대해서는 신경 쓰지 않았습니다. 테스트가 통과되지 않으면 해당 코드가 작동하는지 알 수 없습니다. 대부분의 테스트에는 종속성이 없지만 해당 테스트의 경우 종속성을 분리 할 수 ​​없습니다. 그들이해야한다고 말하기는 쉽지만 단순히 할 수는 없습니다.
Reactgular

4
우리도 마찬가지라고 생각합니다. 통합 테스트에도 "단위 테스트 프레임 워크"(NUnit)를 사용하지만이 두 가지 범주의 테스트 (종종 별도 라이브러리)를 분리해야합니다. 내가 만들려고 한 점은-체크인이 반복 빨간색 - 녹색 - 리팩토링 방법을 따를 때, 그래서 당신은 것을 완전히 격리 될 수 있어야 당신의 단위 테스트 스위트, 하나는 각 이전에 하루에 여러 번 실행한다는 것입니다 수 있습니다 실행 이 테스트는 동료의 발가락을 밟지 않고 하루에 여러 번 테스트합니다.
KeithS

4

코드베이스 어딘가에 원격 DB에 연결하는 실제 작업을 수행하는 코드 줄이 있습니다. 이 코드 라인은 10 번 중 9 번이며, 언어 및 환경에 특정한 런타임 라이브러리가 제공하는 "내장"메소드를 호출합니다. 따라서 "귀하의"코드가 아니므로 테스트 할 필요가 없습니다. 단위 테스트의 목적으로이 메소드 호출이 올바르게 수행 될 것임을 신뢰할 수 있습니다. 단위 테스트 스위트에서 테스트 할 수있는 것과해야 할 일은 연결 문자열이 올바른지 확인하는 것과 같이이 호출에 사용될 매개 변수가 올바른지 확인하는 것과 같은 것입니다. 저장 프로 시저 이름

이것은 단위 테스트가 런타임을 "샌드 박스"로 두지 말고 외부 상태에 의존하지 않아야한다는 제한의 목적 중 하나입니다. 실제로는 매우 실용적입니다. 단위 테스트의 목적은 작성한 코드 (또는 TDD로 작성하려고 하는 코드 )가 생각한대로 동작하는지 확인하는 것입니다. 데이터베이스 작업을 수행하는 데 사용하는 라이브러리와 같이 작성하지 않은 코드는 작성하지 않은 매우 간단한 이유로 단위 테스트 범위에 포함되어서는 안됩니다.

당신의에서 통합 테스트 스위트, 이러한 제한은 완화된다. 지금 당신 수 있습니다작성했던 코드가 그렇지 않은 코드와 잘 작동하는지 확인하기 위해 데이터베이스를 터치하는 디자인 테스트. 그러나이 두 테스트 스위트는 분리 된 상태를 유지해야합니다. 단위 테스트 스위트는 실행 속도가 빠를수록 더 효과적이므로 (개발자가 코드에 대해 작성한 모든 어설 션이 여전히 보유 중인지 신속하게 확인할 수 있음) 거의 통합 테스트 외부 리소스에 대한 종속성이 추가되어 수십 배 느려집니다. 빌드-봇이 몇 시간마다 전체 통합 제품군 실행을 처리하고 외부 리소스를 잠그는 테스트를 실행하여 개발자가 동일한 테스트를 로컬로 실행하여 서로 발가락을 밟지 않도록하십시오. 그리고 빌드가 중단되면 어떻게해야합니까? 빌드-봇이 빌드보다 실패하지 않도록하는 것이 훨씬 더 중요합니다.


이제이를 엄격하게 준수하는 방법은 데이터베이스에 연결하고 쿼리하기위한 정확한 전략에 달려 있습니다. "맨손"데이터 액세스 프레임 워크 (예 : ADO.NET의 SqlConnection 및 SqlStatement 개체)를 사용해야하는 많은 경우에, 사용자가 개발 한 전체 메서드는 기본 제공 메서드 호출 및 이 상황에서 할 수있는 최선의 방법은 전체 기능을 모의하고 통합 테스트 스위트를 신뢰하는 것입니다. 또한 테스트 목적으로 특정 코드 줄을 대체 할 수 있도록 클래스를 어떻게 설계 할 것인지에 달려 있습니다 (예 : "부분적 모의"을 허용하기 때문에 Tobi의 템플릿 메소드 패턴 제안).

데이터 지속성 모델이 데이터 계층의 코드 (예 : 트리거, 저장 프로 시저 등)에 의존하는 경우 데이터 계층 내부에 존재하거나 교차하는 테스트를 개발하는 것 외에 직접 작성하는 코드를 실행하는 다른 방법은 없습니다. 애플리케이션 런타임과 DBMS 간의 경계. 순수 주의자는 이런 이유로 ORM과 같은 것을 선호하여이 패턴을 피해야한다고 말합니다. 나는 그렇게 멀리 갈 것이라고 생각하지 않습니다. 언어 통합 쿼리 및 기타 컴파일러 확인, 도메인 종속 지속성 작업 시대에도 데이터베이스를 저장 프로 시저를 통해 노출 된 작업으로 만 잠그는 것의 가치를 보았으며 물론 이러한 저장 프로시 저는 자동화를 사용하여 확인해야합니다. 테스트. 그러나 이러한 테스트는 단위 테스트 가 아닙니다 . 그들은 통합입니다 테스트.

이 차이에 문제가있는 경우 일반적으로 "단위 테스트 적용 범위"라고하는 완전한 "코드 적용 범위"에 중점을 둡니다. 코드의 모든 줄을 단위 테스트로 처리하고 싶습니다. 얼굴에 고귀한 목표이지만, 나는 hogwash를 말한다; 사고는 실행되지만 그렇지 않은 쓰기 assertionless 테스트까지이 특정 사건을 넘어 스트레칭 안티 패턴,라는 것으로한다는 운동을귀하의 코드. 적용 범위를 위해서만 이러한 유형의 최종 실행은 최소 적용 범위를 완화하는 것보다 더 위험합니다. 코드베이스의 모든 라인이 자동화 된 테스트에 의해 실행되도록하려면 간단합니다. 코드 커버리지 메트릭을 계산할 때는 통합 테스트를 포함하십시오. 한 걸음 더 나아가 이의 제기 된 "Itino"테스트 ( "이름 만 통합")를 분리 할 수 ​​있으며, 유닛 테스트 스위트와이 통합 테스트의 하위 범주 (아직 합리적으로 빠르게 실행되어야 함) 사이에서 대담해야합니다. 전체 범위에 가깝습니다.


2

단위 테스트는 절대 데이터베이스에 연결해서는 안됩니다. 정의에 따라 시스템의 나머지 부분과 완전히 분리 된 단일 코드 단위 (방법)를 테스트해야합니다. 그렇지 않은 경우 단위 테스트가 아닙니다.

의미론을 제외하고, 이것이 유리한 이유는 무수히 많습니다.

  • 테스트가 훨씬 빠르게 진행됩니다
  • 피드백 루프가 즉석이됩니다 (예를 들어, TDD에 대한 <1s 피드백)
  • 빌드 / 배포 시스템에 대해 테스트를 병렬로 실행할 수 있습니다
  • 테스트를 실행하기 위해 데이터베이스가 필요하지 않습니다 (빌드가 훨씬 쉬워 지거나 더 빨라짐)

단위 테스트는 작업을 확인하는 방법입니다. 주어진 방법에 대한 모든 시나리오를 간략히 설명해야합니다. 이는 일반적으로 방법을 통한 모든 다른 경로를 의미합니다. 이중 입력 부기와 유사하게 구축하려는 사양입니다.

설명하는 또 다른 유형의 자동화 테스트는 통합 테스트입니다. 그것들은 또한 매우 중요하지만, 이상적으로는 훨씬 적은 것을 가질 것입니다. 그들은 유닛 그룹이 서로 제대로 통합되어 있는지 확인해야합니다.

그렇다면 데이터베이스 액세스로 어떻게 테스트합니까? 모든 데이터 액세스 코드는 특정 계층에 있어야하므로 응용 프로그램 코드는 실제 데이터베이스 대신 모의 가능한 서비스와 상호 작용할 수 있습니다. 이러한 서비스가 모든 유형의 SQL 데이터베이스, 인 메모리 테스트 데이터 또는 원격 웹 서비스 데이터에 의해 지원되는지는 신경 쓰지 않아야합니다. 그것은 그들의 관심사가 아닙니다.

이상적으로는 (이것은 매우 주관적입니다.) 대량의 코드를 단위 테스트로 다루기를 원합니다. 이것은 각 조각이 독립적으로 작동한다는 확신을줍니다. 일단 조각이 만들어지면 함께 모아야합니다. 예-사용자의 비밀번호를 해시하면 정확한 결과를 얻을 수 있습니다.

각 구성 요소가 대략 5 개의 클래스로 구성되어 있다고 가정 해 보겠습니다. 각 구성 요소 내에서 모든 실패 지점을 테스트하려고합니다. 이것은 모든 것이 올바르게 연결되었는지 확인하기위한 테스트가 훨씬 적습니다. 예-사용자 이름 / 암호가 지정된 데이터베이스에서 사용자를 찾을 수 있는지 테스트하십시오.

마지막으로, 실제로 비즈니스 목표를 달성 할 수 있도록 몇 가지 승인 테스트를 원합니다. 이 중 적은 수가 있습니다. 그들은 응용 프로그램이 실행되고 있는지 확인하고 응용 프로그램을 수행 할 수 있습니다. 예-이 테스트 데이터가 주어지면 로그인 할 수 있어야합니다.

이 세 가지 유형의 테스트를 피라미드로 생각하십시오. 모든 것을 지원하기 위해서는 많은 단위 테스트가 필요합니다.


1

템플릿 메소드 패턴은 도움이 될 수 있습니다.

protected메소드 의 데이터베이스에 대한 호출을 랩핑합니다 . 이 클래스를 테스트하려면 실제 데이터베이스 연결 클래스에서 상속되고 보호 된 메소드를 대체하는 가짜 오브젝트를 실제로 테스트합니다.

이렇게하면 데이터베이스에 대한 실제 호출이 단위 테스트를 거치지 않습니다. 그러나 이것은 몇 줄의 코드 일뿐입니다. 그리고 그것은 받아 들일 수 있습니다.


1
내가 왜 내 자신의 질문에 대답하는지 궁금해하는 경우 : 그렇습니다. 이것은 답 이 수 있지만 그것이 맞는지 확실하지 않습니다.
TobiMcNamobi

-1

외부 데이터를 사용한 테스트는 통합 테스트입니다. 단위 테스트는 단위 만 테스트한다는 의미입니다. 대부분 비즈니스 로직으로 수행됩니다. 코드 단위를 테스트 가능하게하려면 코드의 다른 부분과 독립적 인 단위를 만들어야하는 것처럼 일부 지침을 따라야합니다. 단위 테스트 중에 데이터가 필요한 경우 종속성 주입으로 해당 데이터를 강제로 주입해야합니다. 거기에는 조롱과 스터 빙 프레임 워크가 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.