문제

데이터베이스에 액세스하는 수녀 테스트가 있습니다. 그중 하나가 실패하면 데이터베이스를 일관되지 않은 상태로 남겨 둘 수 있습니다. 모든 테스트 실행에 대해 데이터베이스를 재건하므로 문제가되지 않지만 같은 실행에서 다른 테스트가 실패 할 수 있습니다.

테스트 중 하나가 실패한 것을 감지하고 일종의 정리를 수행 할 수 있습니까?

우리는 모든 테스트에서 정리 코드를 작성하고 싶지 않습니다. 이미 지금 그렇게합니다. 분해시 Perfrom 정리를 원하지만 테스트가 실패한 경우에만 정리 비용이 비싸 질 수 있습니다.

업데이트: 명확히하려면 - 테스트가 간단하고 정리 또는 오류 처리 로직을 포함하지 않기를 바랍니다. 또한 테스트가 실패한 경우에만 모든 테스트 실행에 따라 데이터베이스 재설정을 수행하고 싶지 않습니다. 그리고이 코드는 아마도 파열 방법으로 실행되어야하지만 현재 실패하거나 성공한 테스트가 테스트되면 정보를 얻는 방법을 알지 못합니다.

업데이트 2:

        [Test]
        public void MyFailTest()
        {
            throw new InvalidOperationException();
        }

        [Test]
        public void MySuccessTest()
        {
            Assert.That(true, Is.True);
        }

        [TearDown]
        public void CleanUpOnError()
        {
            if (HasLastTestFailed()) CleanUpDatabase();
        }

HaslastTestFailed ()의 구현을 찾고 있습니다.

도움이 되었습니까?

해결책

이 아이디어는 저에게 관심을 갖게되었으므로 약간 파고 들었습니다. Nunit은 상자 밖에서이 능력을 가지고 있지 않지만 Nunit과 함께 제공되는 전체 확장 성 프레임 워크가 있습니다. 나는 찾았다 수녀 확장에 관한이 훌륭한 기사 - 좋은 출발점이었습니다. 그것과 함께 연주 한 후, 나는 다음 솔루션을 생각해 냈습니다 : 사용자 정의로 장식 된 방법 CleanupOnError 비품의 테스트 중 하나가 실패하면 속성이 호출됩니다.

테스트의 모습은 다음과 같습니다.

  [TestFixture]
  public class NUnitAddinTest
  {
    [CleanupOnError]
    public static void CleanupOnError()
    {
      Console.WriteLine("There was an error, cleaning up...");
      // perform cleanup logic
    }

    [Test]
    public void Test1_this_test_passes()
    {
      Console.WriteLine("Hello from Test1");
    }

    [Test]
    public void Test2_this_test_fails()
    {
      throw new Exception("Test2 failed");
    }

    [Test]
    public void Test3_this_test_passes()
    {
      Console.WriteLine("Hello from Test3");
    }
  }

속성이 간단한 곳 :

  [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
  public sealed class CleanupOnErrorAttribute : Attribute
  {
  }

그리고 다음은 Addin에서 어떻게 실행되는지가 있습니다.

public void RunFinished(TestResult result)
{
  if (result.IsFailure)
  {
    if (_CurrentFixture != null)
    {
      MethodInfo[] methods = Reflect.GetMethodsWithAttribute(_CurrentFixture.FixtureType,
                                                             CleanupAttributeFullName, false);
      if (methods == null || methods.Length == 0)
      {
        return;
      }

      Reflect.InvokeMethod(methods[0], _CurrentFixture);
    }
  }
}

그러나 여기에 까다로운 부분이 있습니다. addin은 다음에 배치해야합니다. addins Nunit 러너 옆에있는 디렉토리. 광산은 TestDriven.net 디렉토리의 Nunit Runner 옆에 배치되었습니다.

C:\Program Files\TestDriven.NET 2.0\NUnit\addins

(나는 그것을 만들었다 addins 디렉토리, 거기에 없음)

편집하다 또 다른 것은 청소 방법이 static!

나는 간단한 addin을 함께 해킹했다, 당신은 소스를 다운로드 할 수 있습니다 내 스카이 드라이브. 참조를 추가해야합니다 nunit.framework.dll, nunit.core.dll 그리고 nunit.core.interfaces.dll 적절한 장소에서.

몇 가지 메모 : 속성 클래스는 코드의 어느 곳에도 배치 할 수 있습니다. 나는 그것을 addin 자체와 같은 어셈블리에 배치하고 싶지 않았다. Core Nunit Assemblies이므로 다른 어셈블리에 배치했습니다. 줄을 바꾸는 것을 잊지 마십시오 CleanAddin.cs, 다른 곳에두기로 결정한 경우.

도움이되기를 바랍니다.

다른 팁

버전 2.5.7 이후 NUNIT를 사용하면 최종 테스트가 실패했는지 여부를 감지 할 수 있습니다. 새로운 TestContext 클래스를 사용하면 테스트가 TestStauts를 포함하여 자신에 대한 정보에 액세스 할 수 있습니다.

자세한 내용은 참조하십시오 http://nunit.org/?p=releasenotes&r=2.5.7

[TearDown]
public void TearDown()
{
    if (TestContext.CurrentContext.Result.Status == TestStatus.Failed)
    {
        PerformCleanUpFromTest();
    }
}

Nunit 에게이 작업을 수행하도록 강요하는 것이 가능할 수 있지만 가장 현명한 디자인은 아니지만 항상 임시 파일을 어딘가에 설정할 수 있으며 해당 파일이 있으면 정리를 실행할 수 있습니다.

데이터베이스 트랜잭션을 활성화하고 테스트가 끝날 때 데이터베이스를 원래 상태로 되돌리도록 코드를 변경하는 것이 좋습니다 (예 : 단위 테스트를 나타내는 트랜잭션을 폐기).

예, 있습니다. 당신은 사용할 수 있습니다 분해 기인하다 각 테스트 후 분해됩니다. 당신은 당신이 가지고있는 해당 데이터베이스 "재설정"스크립트를 적용하고 각 테스트 전후에 찢어지고 다시 설정하려고합니다.

이 속성은 TestFixture 내부에서 사용하여 각 테스트 방법이 실행 된 후 수행되는 공통 기능 세트를 제공합니다.

업데이트: 주석과 질문에 대한 업데이트를 기반으로, 눈물 속성을 사용하고 개인 변수를 사용하여 메소드 내용이 발사되어야하는지 여부를 표시 할 수 있다고 말합니다.

그러나 나는 또한 당신이 복잡한 논리 나 오류 처리 코드를 원하지 않는다는 것을 알았습니다.

그 점을 감안할 때, 나는 표준 설정/분해 당신을 위해 가장 효과적입니다. 오류가 있는지 여부는 중요하지 않으며 오류 처리 코드가 필요하지 않습니다.

다음 테스트가 현재 테스트의 성공적인 완료에 의존하기 때문에 특별한 정리가 필요하다면 테스트를 다시 방문하는 것이 좋습니다. 아마도 서로 의존해서는 안됩니다.

Try-Catch 블록을 사용하여 잡힌 예외를 재고하는 것은 어떻습니까?

try
{
//Some assertion
}
catch
{
     CleanUpMethod();
     throw;
}

나는 PHSR이 제안하는 것을 좋아하고, 당신이 그것을 감당할 수있을 때, 테스트를 리팩터링하여 다른 테스트가 필요로하는 것과 동일한 데이터에 의존 할 필요가 없거나 데이터 액세스 계층을 추상화하고 해당 데이터베이스에서 나오는 결과를 조롱 할 필요가 없습니다. 테스트가 다소 비싸고 데이터베이스에서 모든 쿼리 로직을 수행해야하며 어셈블리의 비즈니스 로직을 수행해야합니다. 결과가 반환 된 결과를 실제로 신경 쓰지 않습니다.

또한 예외 처리를 훨씬 더 잘 테스트 할 수 있습니다.

또 다른 옵션은 예외를 던지는 특수 함수를 갖는 것입니다.

public abstract class CleanOnErrorFixture
{
     protected bool threwException = false;

     protected void ThrowException(Exception someException)
     {
         threwException = true;
         throw someException;
     }

     protected bool HasTestFailed()
     {
          if(threwException)
          {
               threwException = false; //So that this is reset after each teardown
               return true;
          }
          return false;
     }
}

그런 다음 예제를 사용합니다.

[TestFixture]
public class SomeFixture : CleanOnErrorFixture
{
    [Test]
    public void MyFailTest()
    {
        ThrowException(new InvalidOperationException());
    }

    [Test]
    public void MySuccessTest()
    {
        Assert.That(true, Is.True);
    }

    [TearDown]
    public void CleanUpOnError()
    {
        if (HasLastTestFailed()) CleanUpDatabase();
    }
}

여기서 유일한 문제는 스택 추적이 CleanOnerRorfixture로 이어질 것입니다.

지금까지 언급되지 않은 한 가지 옵션 중 하나는 TransactionScope 객체에 테스트를 마무리하는 것이므로 테스트가 DB에 아무것도 촉구하지 않기 때문에 어떤 일이 발생하는지는 중요하지 않습니다.

여기에 있습니다 이 기술에 대한 몇 가지 세부 사항. 단위 테스트 및 트랜잭션 스코프에 대한 검색을 수행하는 경우 더 많은 것을 찾을 수 있습니다 (DB에 도달하면 실제로 통합 테스트를 수행하고 있음). 나는 과거에 그것을 성공적으로 사용했습니다.

이 접근법은 간단하고 정리가 필요하지 않으며 테스트가 분리되도록합니다.

편집- 방금 Ray Hayes의 대답이 나와 비슷하다는 것을 알았습니다.

어떻게 실패합니까? 시도 (테스트) / 캐치 (고정 된 DB 수정) / 마침내 블록에 넣을 수 있습니까?

또는 실패 상태를 확인할 때 개인 방법을 호출하여 고정 할 수 있습니다.

나는 이것이 좋은 생각이라고 말하지는 않지만 효과가 있어야합니다. 주장 실패는 예외 일뿐입니다. 또한 고정구의 모든 테스트가 실행 된 후 한 번만 실행되는 [TestFixTureTearDown] 속성도 있다는 것을 잊지 마십시오.

이 두 가지 사실을 사용하면 테스트에 실패한 경우 플래그를 설정하고 테스트 고정 장치에서 플래그 값을 확인하는 것과 같은 것을 쓸 수 있습니다.

나는 이것을 추천하지 않지만 효과가있을 것입니다. 당신은 실제로 Nunit을 의도 한대로 사용하지는 않지만 그렇게 할 수 있습니다.


[TestFixture]
public class Tests {
     private bool testsFailed = false;

     [Test]
     public void ATest() {
         try {
             DoSomething();
             Assert.AreEqual(....);
         } catch {
            testFailed = true;
         }
     }

     [TestFixtureTearDown]
     public void CleanUp() {
          if (testsFailed) {
              DoCleanup();
          }
     }
}

당신은 추가 할 수 있습니다 [TearDown] 방법
if (TestContext.CurrentContext.Result.Status != TestStatus.Passed)
테스트가 실패하면 일부 코드가 실행됩니다.

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