Nice programing

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

nicepro 2020. 10. 7. 08:16
반응형

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


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

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

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

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

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


내가 아는 한 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경우에만 테스트중인 모든 클래스에 대해 한 번 실행된다. 따라서 두 가지 방법 중에서 정확히 선택하려는 항목에 따라 다릅니다.


나는 같은 대답을 찾고 있었고, 현재 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 treats collection fixtures in much the same way as class fixtures, except that the lifetime of a collection fixture object is longer: it is created before any tests are run in any of the test classes in the collection, and will not be cleaned up until all test classes in the collection have finished running.

Test collections can also be decorated with IClassFixture<>. xUnit.net treats this as though each individual test class in the test collection were decorated with the class fixture.

Test collections also influence the way xUnit.net runs tests when running them in parallel. For more information, see Running Tests in Parallel.

Important note: Fixtures must be in the same assembly as the test that uses them.


There is an easy easy solution. Use the Fody.ModuleInit plugin

https://github.com/Fody/ModuleInit

It's a nuget package and when you install it it adds a new file called ModuleInitializer.cs to the project. There is one static method in here that gets weaved into the assembly after build and is run as soon as the assembly is loaded and before anything is run.

I use this to unlock the software license to a library that I have purchased. I was always forgetting to unlock the license in each test and even forgetting to derive the test from a base class which would unlock it. The bright sparks that wrote this library, instead of telling you it was license locked introduced subtle numerical errors which causes tests to fail or pass when they shouldn't. You would never know if you had correctly unlocked the library or not. So now my module init looks like

/// <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");
    }
}

and all tests that are placed into this assembly will have the license unlocked correctly for them.


To share SetUp/TearDown-code between multiple classes, you can use xUnit's CollectionFixture.

Quote:

To use collection fixtures, you need to take the following steps:

  • Create the fixture class, and put the the startup code in the fixture class constructor.
  • If the fixture class needs to perform cleanup, implement IDisposable on the fixture class, and put the cleanup code in the Dispose() method.
  • Create the collection definition class, decorating it with the [CollectionDefinition] attribute, giving it a unique name that will identify the test collection.
  • Add ICollectionFixture<> to the collection definition class.
  • Add the [Collection] attribute to all the test classes that will be part of the collection, using the unique name you provided to the test collection definition class's [CollectionDefinition] attribute.
  • If the test classes need access to the fixture instance, add it as a constructor argument, and it will be provided automatically.

참고URL : https://stackoverflow.com/questions/12976319/xunit-net-global-setup-teardown

반응형