문제

저는 Rob Connery의 Asp.net MVC 상점을 따라 C#으로 작은 장난감 웹 애플리케이션을 만들어 왔습니다.

나는 IFooRepository라고 부르는 저장소 인터페이스를 발견했습니다. 메소드는 다음과 같습니다.

IQueryable<Foo> GetFoo();
void PersistFoo(Foo foo);

그리고 이에 대한 세 가지 구현이 있습니다.ISqlFooRepository, IFileFooRepostory 및 IMockFooRepository.

또한 몇 가지 테스트 사례도 있습니다.제가 하고 싶지만 아직 방법을 찾지 못한 것은 이 세 가지 구현 각각에 대해 동일한 테스트 사례를 실행하고 각 인터페이스 유형의 각 테스트 통과에 녹색 체크 표시를 하는 것입니다.

예를 들어

[TestMethod]
Public void GetFoo_NotNull_Test()
{
   IFooRepository repository = GetRepository();
   var results = repository. GetFoo();
   Assert.IsNotNull(results);
}

나는 이 테스트 방법이 세 가지 종류의 저장소를 얻을 수 있도록 환경을 약간 변형하여 세 번 실행하기를 원합니다.현재 개인 도우미 메서드 IFooRepository GetRepository()의 구현만 다른 잘라내어 붙여넣은 세 개의 테스트 클래스가 있습니다.분명히 이것은 냄새가 난다.

그러나 잘라내기 및 붙여넣기 방법을 통합하여 중복을 제거할 수는 없습니다. 테스트를 실행하려면 해당 방법이 존재하고 공개되어야 하며 테스트로 표시되어야 하기 때문입니다.

저는 Microsoft 테스트 프레임워크를 사용하고 있으며 가능하다면 계속 사용하고 싶습니다.그러나 MBUnit에서 이를 수행하는 방법에 대한 제안도 관심을 끌 것입니다.

도움이 되었습니까?

해결책

테스트의 구체적인 버전과 IFooRepository를 반환하는 추상 GetRepository 메서드를 포함하는 추상 클래스를 만듭니다.추상 클래스에서 파생되는 세 가지 클래스를 만듭니다. 각 클래스는 적절한 IFooRepository 구현을 반환하는 방식으로 GetRepository를 구현합니다.세 가지 클래스를 모두 테스트 스위트에 추가하면 준비가 완료됩니다.

일부 공급자에 대해 선택적으로 테스트를 실행할 수 있으려면 MbUnit '[FixtureCategory]' 속성을 사용하여 테스트를 분류하는 것이 좋습니다. 제안되는 범주는 '빠름', '느림', 'db' '중요' 및 '중요하지 않음'( 마지막 두 개는 농담입니다. 정직합니다!)

다른 팁

MbUnit에서는 RowTest 특성을 사용하여 테스트에 대한 매개변수를 지정할 수 있습니다.

[RowTest]
[Row(new ThisRepository())]
[Row(new ThatRepository())]
Public void GetFoo_NotNull_Test(IFooRepository repository)
{
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}

3개의 복사하여 붙여넣은 테스트 메서드가 있는 경우 이를 리팩터링(추출 메서드)하여 중복을 제거할 수 있어야 합니다.

즉.이것이 내가 염두에 두었던 것입니다:

private IRepository GetRepository(RepositoryType repositoryType)
{
    switch (repositoryType)
    {   
          case RepositoryType.Sql:
          // return a SQL repository
          case RepositoryType.Mock:
          // return a mock repository
          // etc
    }
}

private void TestGetFooNotNull(RepositoryType repositoryType)
{
   IFooRepository repository = GetRepository(repositoryType);
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}

[TestMethod]
public void GetFoo_NotNull_Sql()
{
   this.TestGetFooNotNull(RepositoryType.Sql);
}

[TestMethod]
public void GetFoo_NotNull_File()
{
   this.TestGetFooNotNull(RepositoryType.File);
}

[TestMethod]
public void GetFoo_NotNull_Mock()
{
   this.TestGetFooNotNull(RepositoryType.Mock);
}
[TestMethod]
public void GetFoo_NotNull_Test_ForFile()
{   
   GetFoo_NotNull(new FileRepository().GetRepository());
}

[TestMethod]
public void GetFoo_NotNull_Test_ForSql()
{   
   GetFoo_NotNull(new SqlRepository().GetRepository());
}


private void GetFoo_NotNull(IFooRepository repository)
{
  var results = repository. GetFoo();   
  Assert.IsNotNull(results);
}

요약하자면 세 가지 방법이 있습니다.

1) 공통 메서드를 호출하는 하나의 라이너로 테스트를 만듭니다(Rick과 Hallgrim의 답변).

2) MBUnit의 RowTest 기능을 사용하여 이를 자동화합니다(Jon Limjap의 답변).여기서도 열거형을 사용하겠습니다.

[RowTest]
[Row(RepositoryType.Sql)]
[Row(RepositoryType.Mock)]
public void TestGetFooNotNull(RepositoryType repositoryType)
{
   IFooRepository repository = GetRepository(repositoryType);
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}

3) 기본 클래스를 사용하고 belugabob으로 답변
이 아이디어를 바탕으로 샘플을 만들었습니다.

public abstract class TestBase
{
    protected int foo = 0;

    [TestMethod]
    public void TestUnderTen()
    {
        Assert.IsTrue(foo < 10);
    }

    [TestMethod]
    public void TestOver2()
    {
        Assert.IsTrue(foo > 2);
    }
}

[TestClass]
public class TestA: TestBase
{
    public TestA()
    {
        foo = 4;
    }
}

[TestClass]
public class TestB: TestBase
{
    public TestB()
    {
        foo = 6;
    }
}

이는 두 개의 테스트 클래스에서 네 개의 합격 테스트를 생성합니다.
3의 장점은 다음과 같습니다.
1) 최소한의 추가 코드, 최소한의 유지 관리
2) 필요한 경우 새 저장소를 연결하기 위한 최소한의 입력 - 다른 저장소와 달리 한 곳에서 수행됩니다.

단점은 다음과 같습니다.
1) 필요한 경우 공급자에 대해 테스트를 실행하지 않는 유연성이 떨어집니다.
2) 읽기가 더 어렵다.

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