xUnit.net : 글로벌 설정 + 분해?


98

이 질문은 단위 테스트 프레임 워크 xUnit.net에 관한 것 입니다.

테스트가 실행되기 전에 일부 코드를 실행해야하고 모든 테스트가 완료된 후 일부 코드도 실행해야합니다. 전역 초기화 및 종료 코드를 나타내는 일종의 속성 또는 마커 인터페이스가 있어야한다고 생각했지만 찾을 수 없었습니다.

또는 프로그래밍 방식으로 xUnit을 호출하면 다음 코드를 사용하여 원하는 것을 얻을 수도 있습니다.

static void Main()
{
    try
    {
        MyGlobalSetup();
        RunAllTests();  // What goes into this method?
    }
    finally
    {
        MyGlobalTeardown();
    }
}

누구나 전역 설정 / 해체 코드를 선언적으로 또는 프로그래밍 방식으로 실행하는 방법에 대한 힌트를 제공 할 수 있습니까?


1
나는 여기에 대답이 있다고 생각한다 : stackoverflow.com/questions/12379949/…
the_joric

답변:


118

내가 아는 한 xUnit에는 전역 초기화 / 해체 확장 점이 없습니다. 그러나 쉽게 만들 수 있습니다. IDisposable생성자에서 초기화 를 구현 하고 수행 하는 기본 테스트 클래스를 만들고 IDisposable.Dispose메서드 에서 분해를 수행하면 됩니다. 이것은 다음과 같습니다.

public abstract class TestsBase : IDisposable
{
    protected TestsBase()
    {
        // Do "global" initialization here; Called before every test method.
    }

    public void Dispose()
    {
        // Do "global" teardown here; Called after every test method.
    }
}

public class DummyTests : TestsBase
{
    // Add test methods
}

그러나 기본 클래스 설정 및 해제 코드는 각 호출에 대해 실행됩니다. 이것은 매우 효율적이지 않기 때문에 원하는 것이 아닐 수도 있습니다. 더 최적화 된 버전은 IClassFixture<T>인터페이스를 사용하여 전역 초기화 / 해체 기능이 한 번만 호출되도록합니다. 이 버전의 경우 테스트 클래스에서 기본 클래스를 확장하지 않고 조명기 클래스를 참조 하는 IClassFixture<T>인터페이스를 구현합니다 T.

using Xunit;

public class TestsFixture : IDisposable
{
    public TestsFixture ()
    {
        // Do "global" initialization here; Only called once.
    }

    public void Dispose()
    {
        // Do "global" teardown here; Only called once.
    }
}

public class DummyTests : IClassFixture<TestsFixture>
{
    public DummyTests(TestsFixture data)
    {
    }
}

의 생성자가 발생할 TestsFixture경우에만 테스트중인 모든 클래스에 대해 한 번 실행된다. 따라서 두 가지 방법 중에서 정확히 선택하려는 항목에 따라 다릅니다.


4
IUseFixture가 더 이상 존재하지 않고 IClassFixture로 대체 된 것 같습니다.
GaTechThomas

9
이것이 작동하는 동안 Geir Sagberg의 답변에있는 CollectionFixture가이 목적을 위해 특별히 설계되었으므로이 시나리오에 더 적합하다고 생각합니다. 당신은 또한 당신이 단순히 그들을 표시, 테스트 클래스를 상속하지 않는 [Collection("<name>")]속성
MichelZ

8
비동기 설정 및 해체를 수행하는 방법이 있습니까?
안드리

MS가 IClassFixture 솔루션도 구현 한 것 같습니다. docs.microsoft.com/en-us/aspnet/core/test/...
이브라힘

3
XUnit은 테스트 메서드 별, 테스트 클래스 별 및 여러 테스트 클래스에 걸친 세 가지 초기화 옵션을 제공합니다. 문서는 여기에 있습니다 : xunit.net/docs/shared-context
GHN

48

나는 같은 대답을 찾고 있었고, 현재 xUnit 문서는 클래스 또는 클래스 그룹 수준에서 개발자에게 광범위한 설정 / 해체 기능을 제공하는 클래스 고정 및 컬렉션 고정을 구현하는 방법과 관련하여 매우 유용합니다. 이것은 Geir Sagberg의 답변과 일치하며 어떻게 생겼는지 설명하는 훌륭한 골격 구현을 제공합니다.

https://xunit.github.io/docs/shared-context.html

컬렉션 픽스처 사용시기 : 단일 테스트 컨텍스트를 생성하여 여러 테스트 클래스의 테스트간에 공유하고 테스트 클래스의 모든 테스트가 완료된 후 정리하도록 할 때.

때로는 여러 테스트 클래스간에 조명기 객체를 공유하고 싶을 것입니다. 클래스 픽스처에 사용 된 데이터베이스 예제는 좋은 예입니다. 테스트 데이터 세트로 데이터베이스를 초기화 한 다음 여러 테스트 클래스에서 사용할 수 있도록 해당 테스트 데이터를 그대로 둘 수 있습니다. xUnit.net의 컬렉션 픽스처 기능을 사용하여 여러 테스트 클래스의 테스트간에 단일 개체 인스턴스를 공유 할 수 있습니다.

수집 설비를 사용하려면 다음 단계를 수행해야합니다.

조명기 클래스를 만들고 조명기 클래스 생성자에 시작 코드를 넣습니다. 조명기 클래스가 정리를 수행해야하는 경우 조명기 클래스에서 IDisposable을 구현하고 Dispose () 메서드에 정리 코드를 넣습니다. 컬렉션 정의 클래스를 만들고 [CollectionDefinition] 속성으로 장식하고 테스트 컬렉션을 식별 할 고유 한 이름을 지정합니다. 컬렉션 정의 클래스에 ICollectionFixture <>를 추가합니다. 테스트 컬렉션 정의 클래스의 [CollectionDefinition] 특성에 제공 한 고유 이름을 사용하여 컬렉션의 일부가 될 모든 테스트 클래스에 [Collection] 특성을 추가합니다. 테스트 클래스가 픽스처 인스턴스에 액세스해야하는 경우 생성자 인수로 추가하면 자동으로 제공됩니다. 다음은 간단한 예입니다.

public class DatabaseFixture : IDisposable
{
    public DatabaseFixture()
    {
        Db = new SqlConnection("MyConnectionString");

        // ... initialize data in the test database ...
    }

    public void Dispose()
    {
        // ... clean up test data from the database ...
    }

    public SqlConnection Db { get; private set; }
}

[CollectionDefinition("Database collection")]
public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
{
    // This class has no code, and is never created. Its purpose is simply
    // to be the place to apply [CollectionDefinition] and all the
    // ICollectionFixture<> interfaces.
}

[Collection("Database collection")]
public class DatabaseTestClass1
{
    DatabaseFixture fixture;

    public DatabaseTestClass1(DatabaseFixture fixture)
    {
        this.fixture = fixture;
    }
}

[Collection("Database collection")]
public class DatabaseTestClass2
{
    // ...
}

xUnit.net은 컬렉션 픽스처 객체의 수명이 더 길다는 점을 제외하고는 클래스 픽스처와 거의 동일한 방식으로 컬렉션 픽스처를 취급합니다. 컬렉션의 테스트 클래스에서 테스트가 실행되기 전에 생성되며 정리되지 않습니다. 컬렉션의 모든 테스트 클래스 실행이 완료 될 때까지

테스트 컬렉션은 IClassFixture <>로 장식 할 수도 있습니다. xUnit.net은이를 테스트 컬렉션의 각 개별 테스트 클래스가 클래스 픽스처로 장식 된 것처럼 취급합니다.

테스트 컬렉션은 병렬로 실행할 때 xUnit.net이 테스트를 실행하는 방식에도 영향을줍니다. 자세한 내용은 병렬 테스트 실행을 참조하십시오.

중요 참고 사항 : Fixture는이를 사용하는 테스트와 동일한 어셈블리에 있어야합니다.


1
"테스트 컬렉션은 IClassFixture <>로 장식 할 수도 있습니다. xUnit.net은이를 테스트 컬렉션의 각 개별 테스트 클래스가 클래스 고정 장치로 장식 된 것처럼 취급합니다." 그 예를 얻을 수 있을까요? 나는 그것을 잘 이해하지 못한다.
rtf

@TannerFaulkner 클래스 픽스쳐는 테스트 초기화 방법이있을 때 전통적인 .net 단위 테스트 프로젝트에서 얻는 것과 같이 클래스 수준 설정 및 해체를하는 방법이었습니다. [TestInitialize] public void Initialize () {
Larry Smith

내가 가진 유일한 문제 Collection는 "글로벌"설정이 발생하기 위해 속성으로 테스트 클래스를 장식해야한다는 것 입니다. 즉, -any- 테스트를 실행하기 전에 설정하려는 항목이 있으면이 속성을 사용하여 -all- 테스트 클래스를 장식해야합니다. 단일 테스트 클래스를 장식하는 것을 잊으면 추적하기 어려운 오류가 발생할 수 있기 때문에 이것은 제 생각에 너무 취약합니다. xUnit이 진정한 글로벌 설정 및 해체 방법을 만들었다면 좋을 것입니다.
Zodman

13

쉬운 해결책이 있습니다. Fody.ModuleInit 플러그인 사용

https://github.com/Fody/ModuleInit

그것은 너겟 패키지이며 설치 ModuleInitializer.cs하면 프로젝트에 호출되는 새 파일을 추가합니다 . 여기에는 빌드 후 어셈블리로 짜여지고 어셈블리가로드 되 자마자 어떤 것이 실행되기 전에 실행되는 정적 메서드가 하나 있습니다.

구입 한 라이브러리에 대한 소프트웨어 라이센스를 잠금 해제하는 데 사용합니다. 나는 항상 각 테스트에서 라이센스를 잠금 해제하는 것을 잊고 있었고 심지어 잠금을 해제 할 기본 클래스에서 테스트를 파생시키는 것도 잊었습니다. 이 라이브러리를 작성한 밝은 불꽃은 라이센스가 잠겨 있다는 것을 알리는 대신 미묘한 숫자 오류를 일으켜 테스트가 실패하거나 통과하지 않아야 할 때 통과합니다. 라이브러리를 올바르게 잠금 해제했는지 여부는 알 수 없습니다. 이제 내 모듈 초기화는 다음과 같습니다.

/// <summary>
/// Used by the ModuleInit. All code inside the Initialize method is ran as soon as the assembly is loaded.
/// </summary>
public static class ModuleInitializer
{
    /// <summary>
    /// Initializes the module.
    /// </summary>
    public static void Initialize()
    {
            SomeLibrary.LicenceUtility.Unlock("XXXX-XXXX-XXXX-XXXX-XXXX");
    }
}

이 어셈블리에 배치 된 모든 테스트에는 라이선스가 올바르게 잠금 해제됩니다.


2
탄탄한 아이디어; 불행히도 아직 DNX 단위 테스트에서 작동하지 않는 것 같습니다.
Jeff Dunlop

12

여러 클래스간에 SetUp / TearDown 코드를 공유하려면 xUnit의 CollectionFixture를 사용할 수 있습니다 .

인용문:

수집 설비를 사용하려면 다음 단계를 수행해야합니다.

  • 조명기 클래스를 만들고 조명기 클래스 생성자에 시작 코드를 넣습니다.
  • 조명기 클래스가 정리를 수행해야하는 경우 조명기 클래스에서 IDisposable을 구현하고 Dispose () 메서드에 정리 코드를 넣습니다.
  • 컬렉션 정의 클래스를 만들고 [CollectionDefinition] 속성으로 장식하고 테스트 컬렉션을 식별 할 고유 한 이름을 지정합니다.
  • 컬렉션 정의 클래스에 ICollectionFixture <>를 추가합니다.
  • 테스트 컬렉션 정의 클래스의 [CollectionDefinition] 특성에 제공 한 고유 이름을 사용하여 컬렉션의 일부가 될 모든 테스트 클래스에 [Collection] 특성을 추가합니다.
  • 테스트 클래스가 픽스처 인스턴스에 액세스해야하는 경우 생성자 인수로 추가하면 자동으로 제공됩니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.