저장소 패턴이있는 TDD


10

새 프로젝트에서 TDD로 시도하기로 결정했습니다. 그리고 처음에는 문제가 발생했습니다. 응용 프로그램에서 가장 먼저해야 할 일은 데이터 소스에서 데이터를 읽는 기능을 제공하는 것입니다. 이를 위해 리포지토리 패턴을 사용하고 싶습니다. 그리고 지금:

  • 테스트가 저장소 인터페이스의 실제 구현을위한 것이라면 데이터베이스에 액세스 할 수있는 클래스를 테스트 할 것이므로 피해야한다는 것을 알고 있습니다.
  • 테스트가 리포지토리 패턴의 실제 구현이 아닌 경우 테스트를 잘합니다. 모의입니다. 해당 단위 테스트에서 테스트 된 프로덕션 코드는 없습니다.

나는 이틀부터 이것에 대해 생각하고 있으며 여전히 합리적인 해결책을 제시 할 수 없습니다. 내가해야 할 일?

답변:


11

리포지토리는 도메인에서 NHibernate 또는 Doctrine과 같은 DAL 프레임 워크 또는 SQL 실행 클래스로 변환됩니다. 즉, 저장소는 해당 프레임 워크에서 해당 작업을 수행하기 위해 메소드를 호출합니다. 저장소는 데이터를 가져 오는 데 필요한 쿼리를 구성합니다. ORM 프레임 워크를 사용하지 않는 경우 (당신의 희망은 ...), 저장소는 원시 SQL 문이 작성되는 장소가됩니다.

이러한 방법 중 가장 기본적인 방법은 저장입니다. 대부분의 경우 이는 단순히 저장소에서 작업 단위 (또는 세션)로 오브젝트를 전달합니다.

public void Save(Car car)
{
    session.Save(car);
}

그러나 ID로 자동차를 가져 오는 것과 같은 다른 예를 살펴 보겠습니다. 다음과 같이 보일 수 있습니다

public function GetCarWithId(String id)
{
    return Session.QueryOver<Car>()
                    .Where(x => x.Id == id)
                    .SingleOrDefault();
}

여전히 복잡하지는 않지만 여러 조건으로 상상할 수 있습니다 ( 'Volkswagen'그룹의 모든 브랜드에 대해 2010 년 이후에 만들어진 모든 자동차를 가져 오십시오). 따라서 진정한 TDD 방식으로이를 테스트해야합니다. 이를 수행하는 몇 가지 방법이 있습니다.

옵션 1 : ORM 프레임 워크에 대한 호출을 조롱

물론 Session 개체를 조롱하고 올바른 호출이 이루어 졌다고 간단히 주장 할 수 있습니다. 이것은 저장소를 테스트하는 동안 저장소가 원하는 방식으로 내부적으로 보이는지 테스트하기 때문에 실제로 테스트 중심 이 아닙니다 . 테스트는 기본적으로 '코드는 다음과 같아야합니다'라고 말합니다. 여전히 유효한 접근 방법이지만 이러한 종류의 테스트에는 가치가 거의 없다고 생각합니다.

옵션 2 : 테스트에서 데이터베이스를 (다시) 빌드

일부 DAL 프레임 워크에서는 도메인을 테이블에 매핑하기 위해 만든 매핑 파일을 기반으로 데이터베이스의 전체 구조를 구축 할 수 있습니다. 이러한 프레임 워크의 경우 리포지토리를 테스트하는 방법은 테스트의 첫 단계에서 메모리 내 데이터베이스로 데이터베이스를 만들고 DAL 프레임 워크를 사용하여 개체를 메모리 내 데이터베이스에 추가하는 것입니다. 그런 다음 인 메모리 데이터베이스의 저장소를 사용하여 메소드가 작동하는지 테스트 할 수 있습니다. 이 테스트는 느리지 만 매우 유효하며 테스트를 주도합니다. DAL 프레임 워크와의 협조가 필요합니다.

옵션 3 : 실제 데이터베이스에서 테스트

또 다른 방법은 실제 데이터베이스를 테스트하고 단위 테스트를 분리하는 것입니다. 트랜잭션으로 테스트를 둘러싸고, 수동으로 정리하고 (유지하기가 매우 권장되지는 않음), 각 단계 후에 데이터베이스를 완전히 다시 빌드하십시오 ... 빌드하는 애플리케이션에 따라 가능하지 않다. 내 응용 프로그램에서 소스 제어에서 로컬 개발 데이터베이스를 완벽하게 구축 할 수 있으며 리포지토리의 단위 테스트는 트랜잭션을 사용하여 테스트를 서로 완전히 분리합니다 (오픈 트랜잭션, 데이터 삽입, 테스트 리포지토리, 롤백 트랜잭션). 모든 빌드는 먼저 로컬 개발 데이터베이스를 설정 한 다음 해당 로컬 개발 데이터베이스의 리포지토리에 대한 트랜잭션 격리 단위 테스트를 수행합니다. 그것'

DAL을 테스트하지 마십시오

NHibernate와 같은 DAL 프레임 워크를 사용하는 경우 해당 프레임 워크를 테스트 할 필요가 없습니다. 도메인 객체를 저장, 검색 및 비교하여 모든 것이 정상인지 확인하기 위해 매핑 파일을 테스트 할 수 있지만 (캐싱을 비활성화해야 함) 작성해야 할 다른 많은 테스트만큼 필요하지는 않습니다. 나는 아이들에 대한 조건을 가진 부모의 컬렉션에 주로 이것을하는 경향이 있습니다.

리포지토리의 반환을 테스트 할 때 도메인 개체의 일부 식별 속성이 일치하는지 간단히 확인할 수 있습니다. 이것은 ID 일 수 있지만 테스트에서 사람이 읽을 수있는 속성을 확인하는 것이 더 유리합니다. '2010 년 이후에 만든 모든 차를 가져 오십시오.'에서 이것은 단순히 5 대의 차가 반환되고 번호판이 '여기에 목록 삽입'인지 확인합니다. 추가 이점은 정렬에 대해 생각하게하고 테스트가 자동으로 정렬을 강제한다는 것입니다. 여러 번 정렬 (데이터베이스에서 정렬 된 반환, 뷰 객체를 만들기 전에 정렬 한 다음 뷰 객체를 모두 동일한 경우에 같은 경우에 정렬)하는 응용 프로그램이 몇 개인 지 또는 놀랍게도 저장소 정렬을 가정하고 실수로 제거 하는 응용 프로그램 수에 놀랄 것입니다. UI를 깨고 길을 따라 일부.

'단위 테스트'는 단지 이름입니다

제 생각에 단위 테스트는 대부분 데이터베이스에 영향을 미치지 않아야 합니다. 소스의 데이터를 필요로하는 모든 코드가 저장소에서이를 수행하고 해당 저장소가 종속성으로 삽입되도록 응용 프로그램을 빌드합니다. 이를 통해 쉽게 조롱하고 원하는 모든 TDD 장점을 얻을 수 있습니다. 그러나 결국 당신은 당신의 저장소가 그들의 의무를 수행하고 있는지 확인하기를 원하며, 가장 쉬운 방법이 데이터베이스에 도달한다면, 그렇게하십시오. 나는 '단위 테스트가 데이터베이스에 닿아서는 안된다'는 개념을 오랫동안 버려두고 이것을해야 할 진짜 이유가 있다는 것을 배웠다. 그러나 자동 및 반복적 으로이 작업을 수행 할 수있는 경우에만. 그리고 우리가 그러한 테스트를 '단위 테스트'또는 '통합 테스트'라고 부르는 날씨는 헛소리입니다.


3
단위 테스트와 통합 테스트는 목적이 다릅니다. 이 테스트의 이름은 단순한 장식적인 것이 아닙니다. 그들은 또한 설명 적입니다.
Robert Harvey

9
  1. 사소하거나 명백한 저장소 방법을 테스트하지 마십시오.

    메소드가 사소한 CRUD 조작 인 경우 실제로 테스트하는 것은 매개 변수가 올바르게 맵핑되는지 여부입니다. 통합 테스트가있는 경우 이러한 오류가 즉시 명백해집니다.

    이것은 다음과 같은 사소한 속성에 적용되는 것과 동일한 원칙입니다.

    public property SomeProperty
    {
        get { return _someProperty; }
        set { _someProperty = value; }
    }
    

    테스트 할 것이 없기 때문에 테스트하지 않습니다. 속성에 확인해야 할 유효성 검사 또는 기타 논리가 없습니다.

  2. 여전히 이러한 방법을 테스트하려면 ...

    mocks는 그것을하는 방법입니다. 이것들은 단위 테스트입니다. 단위 테스트로는 데이터베이스를 테스트하지 않습니다. 이것이 바로 통합 테스트입니다.

추가 정보
전체 스택, 3 부 : TDD를 사용하여 리포지토리 구축 (약 16 분 후 시청 시작).


3
물론 이해합니다. 그래도 TDD 방식이라면 먼저이 코드에 대한 테스트가 없다면 코드를 작성해서는 안됩니다.
Thaven

1
@Thaven-YouTube에 "tdd dead?"라는 제목의 동영상이 있습니다. 조심해 그들은 많은 흥미로운 점을 다루고 있는데, 그 중 하나는 응용 프로그램의 모든 수준에서 TDD를 적용하는 것이 반드시 최고의 아이디어는 아니라는 개념입니다. "실패한 테스트가없는 코드 없음"은 너무 극단적 인 입장이며 결론 중 하나입니다.
Jules

2
@ 줄스 : tl; dw는 무엇입니까?
Robert Harvey

1
@RobertHarvey 요약하기는 어렵지만, 가장 중요한 요점은 TDD를 항상 준수해야하는 종교로 취급하는 것은 실수라는 것입니다. 그것을 사용하는 선택은 트레이드 오프의 일부이며, (1) 어떤 문제에서 더 빨리 일할 수 있고 (2) 필요한 것보다 더 복잡한 해결책으로 당신을 밀어 낼 수 있다는 것을 고려해야합니다. 특히 모의를 많이 사용한다면
Jules

1
포인트 # 1의 경우 +1 테스트는 틀릴 수 있습니다. 단지 보통 사소한 것입니다. 정확성이 테스트보다 명확한 기능을 테스트하는 것은 의미가 없습니다. 100 % 코드 적용 범위를 확보하는 것이 프로그램의 가능한 모든 실행을 테스트하는 데 가까운 곳이 아니므로 테스트 노력을 기울이는 장소에 대해서도 현명 할 수 있습니다.
Doval
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.