code

.NET에서 실제 파일과 통합 테스트를 수행하는 방법은 무엇입니까?

codestyles 2020. 12. 31. 08:17
반응형

.NET에서 실제 파일과 통합 테스트를 수행하는 방법은 무엇입니까?


파일 시스템 및 파일과 관련된 논리를 구현하는 클래스가 있습니다. 예를 들어,이 논리의 일부로 다음 작업을 수행하고 있습니다.

  • 특정 폴더에 특정 구조가 있는지 확인 (예 : 특정 이름을 가진 하위 폴더 포함 등)
  • 해당 폴더에서 일부 파일을로드하고 구조 확인 (예 : 특정 폴더 내의 특정 위치에있는 일부 구성 파일 임)
  • 구성 파일에서 테스트 / 검증을위한 추가 파일로드 (예 :이 구성 파일에는 다른 내부 구조 등을 가져야하는 동일한 폴더의 다른 파일에 대한 정보가 포함되어 있습니다.)

이제이 모든 로직에는 몇 가지 워크 플로가 있으며 문제가있는 경우 예외가 발생합니다 (예 : 특정 폴더 위치에서 구성 파일을 찾을 수 없음). 또한 이 논리에 관련된 MEF (Managed Extensibility Framework)가 있습니다. 확인중인 이러한 파일 중 일부는 MEF 집계 등에 수동으로로드하는 관리 DLL이기 때문입니다.

이제이 모든 것을 어떤 식 으로든 테스트하고 싶습니다. 다양한 테스트 사례를 다루는 HDD에 여러 개의 물리적 테스트 폴더를 만들고 이에 대해 내 코드를 실행할 생각이었습니다. 예를 들어 만들 수 있습니다.

  • 올바른 구조와 모든 파일이 유효한 폴더
  • 구조가 정확하지만 구성 파일이 잘못된 폴더
  • 구조가 정확하지만 구성 파일이 누락 된 폴더 등 ...

이것이 올바른 접근 방식일까요? 이 시나리오에서 내 코드를 정확히 실행하는 방법을 잘 모르겠습니다. 전체 응용 프로그램을 실행하고 이러한 모의 폴더를 확인하도록 지정하고 싶지는 않습니다. 이러한 파일 시스템 개체에 대해 내 코드를 실행하는 일종의 "단위 테스트"를 작성하기 위해 일부 단위 테스트 프레임 워크를 사용해야합니까?

일반적으로이 모든 것이 이러한 종류의 테스트 시나리오에 대한 올바른 접근 방식입니까? 다른 더 나은 접근 방식이 있습니까?


우선 , 외부 리소스를 건드리지 않고 로직을 테스트하는 단위 테스트를 작성 하는 것이 좋습니다 . 여기에는 두 가지 옵션이 있습니다.

  1. 추상화 계층을 사용하여 논리를 파일 시스템과 같은 외부 종속성으로부터 격리해야합니다. 단위 테스트에서이 추상화를 쉽게 스텁 또는 모의 (손으로 또는 NSubstitute, FakeItEasy 또는 Moq와 같은 제한된 격리 프레임 워크의 도움으로) 할 수 있습니다. 이 경우 테스트를 통해 더 나은 설계를 할 수 있기 때문에이 옵션을 선호합니다.
  2. 레거시 코드를 처리해야하는 경우 (이 경우에만), 거의 모든 것을 스텁 / 모의 할 수있는 (예 : 봉인 및 정적) 제약없는 격리 프레임 워크 (예 : TypeMock Isolator, JustMock 또는 Microsoft Fakes) 중 하나를 사용할 수 있습니다. 클래스, 비가 상 메서드). 그러나 그들은 돈이 든다. 유일한 "무료"옵션은 Visual Studio 2012/2013 Premium / Ultimate의 행복한 소유자가 아니라면 Microsoft Fakes입니다.

단위 테스트에서는 MEF와 같은 외부 라이브러리의 논리를 테스트 할 필요가 없습니다.

둘째 , 통합 테스트 를 작성하려면 "행복한 경로"테스트 (모든 것이 정상일 때)와 경계 케이스 (파일 또는 디렉토리를 찾을 수 없음)에서 논리를 테스트하는 일부 테스트를 작성해야합니다. @Sergey Berezovskiy와 달리 각 테스트 사례에 대해 별도의 폴더를 만드는 것이 좋습니다 . 주요 장점은 다음과 같습니다.

  1. 의도를 더 명확하게 표현하는 의미있는 이름을 폴더에 지정할 수 있습니다.
  2. 복잡한 (즉, 깨지기 쉬운) 설정 / 해체 로직을 작성할 필요가 없습니다.
  3. 나중에 다른 폴더 구조를 사용하기로 결정한 경우에도 이미 작동중인 코드와 테스트가 있기 때문에 더 쉽게 변경할 수 있습니다 (테스트 하네스에서 리팩토링하는 것이 훨씬 더 쉽습니다).

단위 및 통합 테스트 모두에 대해 일반 단위 테스트 프레임 워크 (예 : NUnit 또는 xUnit.NET)를 사용할 수 있습니다 . 이 프레임 워크를 사용하면 빌드 서버의 지속적 통합 시나리오에서 테스트를 실행하기가 매우 쉽습니다.

두 종류의 테스트를 모두 작성하기로 결정한 경우 통합 테스트에서 단위 테스트를 분리해야합니다 (모든 종류의 테스트에 대해 별도의 프로젝트를 만들 수 있음). 그 이유 :

  1. 단위 테스트 는 개발자를위한 안전망입니다. 마지막 코드 변경 (버그 수정, 새로운 기능) 후 시스템 장치의 예상 동작에 대한 빠른 피드백을 제공해야합니다. 자주 실행되는 경우 개발자는 시스템을 손상시킨 코드를 빠르고 쉽게 식별 할 수 있습니다. 아무도 느린 단위 테스트를 실행하고 싶지 않습니다.
  2. 통합 테스트 는 일반적으로 단위 테스트보다 느립니다. 그러나 그들은 다른 목적을 가지고 있습니다. 그들은 단위가 실제 종속성과 함께 예상대로 작동하는지 확인합니다.

인터페이스 뒤에있는 파일 시스템에 대한 호출을 추상화하여 단위 테스트로 가능한 한 많은 논리를 테스트해야합니다. 의존성 주입과 FakeItEasy 와 같은 테스트 프레임 워크 를 사용하면 인터페이스가 실제로 사용 / 호출되어 파일 및 폴더에서 작동하는지 테스트 할 수 있습니다.

그러나 언젠가는 파일 시스템에서도 작동하는 구현을 테스트해야하며 여기에서 통합 테스트가 필요합니다.

테스트해야하는 것은 자신의 파일 시스템에있는 자신의 파일과 디렉터리뿐이므로 테스트해야하는 항목은 상대적으로 고립 된 것 같습니다 . 데이터베이스 또는 여러 사용자가있는 다른 외부 시스템 등을 테스트하려는 경우 상황이 더 복잡 할 수 있습니다.

이 유형의 통합 테스트를 가장 잘 수행하는 방법에 대한 "공식 규칙"을 찾을 수 없을 것 같지만 올바른 방향으로 가고 있다고 생각합니다. 노력해야 할 몇 가지 아이디어 :

  • 명확한 표준 : 각 테스트의 규칙과 목적을 명확하게합니다.
  • 자동화 : 너무 많은 수동 조정없이 신속하게 테스트를 다시 실행할 수있는 기능.
  • 반복성 : "재설정"할 수있는 테스트 상황으로, 약간의 변화만으로 테스트를 신속하게 재실행 할 수 있습니다.

반복 가능한 테스트 시나리오 만들기

귀하의 상황에서 저는 두 개의 주요 폴더를 설정할 것입니다. 하나는 모든 것이 정상인 (즉, 올바르게 작동하는) 폴더이고 다른 하나는 모든 규칙이 위반 된 폴더입니다.

이 폴더와 그 안에 파일을 만든 다음 각 폴더를 압축하고 각각의 압축을 풀기위한 논리를 테스트 클래스에 작성합니다.

이것은 실제로 테스트가 아닙니다. 대신 테스트 시나리오를 설정하기위한 "스크립트"라고 생각하면 기본 통합 테스트가 테스트 중에 변경되거나 엉망이 되더라도 폴더와 파일을 쉽고 빠르게 삭제하고 다시 만들 수 있습니다. 그것들을 테스트 클래스에 넣는 이유는 단순히 테스트 중에 작업하게 될 동일한 인터페이스에서 쉽게 실행할 수 있도록하기 위해서입니다.

테스팅

각 상황에 대해 한 세트 씩 두 세트의 테스트 클래스를 만듭니다 (규칙을 위반 한 폴더와 폴더를 올바르게 설정). 상황의 복잡성에 따라 의미있는 폴더 계층 구조에 이러한 테스트를 배치합니다.

단위 / 통합 테스트에 얼마나 익숙한지는 분명하지 않습니다. 어쨌든 NUnit 을 추천 합니다. 확장 기능도 사용하고 싶습니다 Should. Nuget에서이 두 가지를 모두 얻을 수 있습니다.

install-package Nunit
install-package Should

should-package를 사용하면 다음과 같은 방식으로 테스트 코드를 작성할 수 있습니다.

someCalculatedIntValue.ShouldEqual(3); 
someFoundBoolValue.ShouldBeTrue();

테스트를 실행하는 데 사용할 수있는 여러 테스트 실행자가 있습니다. 개인적으로 Resharper에 내장 된 주자에 대한 실제 경험이 있었지만 만족스럽고 추천하는 데 문제가 없습니다.

Below is an example of a simple test-class with two tests. Note that in the first, we check for an expected value using an extension method from Should, while we don't explicitly test anything in the second. That is because it is tagged with [ExpectedException], meaning it will fail if an Exception of the specified type is not thrown when the test is run. You can use this to verify that an appropriate exception is thrown whenever one of your rules is broken.

[TestFixture] 
public class When_calculating_sums
{                    
    private MyCalculator _calc;
    private int _result;

    [SetUp] // Runs before each test
    public void SetUp() 
    {
        // Create an instance of the class to test:
        _calc = new MyCalculator();

        // Logic to test the result of:
        _result = _calc.Add(1, 1);
    }

    [Test] // First test
    public void Should_return_correct_sum() 
    {
        _result.ShouldEqual(2);
    }

    [Test] // Second test
    [ExpectedException(typeof (DivideByZeroException))]
    public void Should_throw_exception_for_invalid_values() 
    {
        // Divide by 0 should throw a DivideByZeroException:
        var otherResult = _calc.Divide(5, 0);
    }       

    [TearDown] // Runs after each test (seldom needed in practice)
    public void TearDown() 
    {
        _calc.Dispose(); 
    }
}

With all of this in place, you should be able to create and recreate test-scenarios, and run tests on them in a easy and repeatable way.


Edit: As pointed out in a comment, Assert.Throws() is another option for ensuring exceptions are thrown as required. Personally, I like the tag-variant though, and with parameters, you can check things like the error message there too. Another example (assuming a custom error message is being thrown from your calculator):

[ExpectedException(typeof(DivideByZeroException), 
   ExpectedMessage="Attempted to divide by zero" )]
public void When_attempting_something_silly(){  
    ...
}

I'd go with single test folder. For various test cases you can put different valid/invalid files into that folder as part of context setup. In test teardown just remove those files from folder.

E.g. with Specflow:

Given configuration file not exist
When something
Then foo

Given configuration file exists
And some dll not exists
When something
Then bar

Define each context setup step as copying/not copying appropriate file to your folder. You also can use table for defining which file should be copied to folder:

Given some scenario
| FileName         |
| a.config         |
| b.invalid.config |
When something
Then foobar

I don't know your program's architecture to give a good advice, but I will try

  1. I believe that you don't need to test real file structure. File access services are defined by system/framework, and they're don't need to be tested. You need to mock this services in related tests.
  2. Also you don't need to test MEF. It is already tested.
  3. Use SOLID principles to make unit tests. Especially take look at Single Responsibility Principle this will allow you to to create unit tests, which won't be related to each others. Just don't forget about mocking to avoid dependencies.
  4. To make integration tests, you can create a set of helper classes, which will emulate scenarios of file structures, which you want to test. This will allow you to stay not attached to machine on which you will run this tests. Such approach maybe more complicated than creating real file structure, but I like it.

I would build framework logic and test concurrency issues and file system exceptions to ensure a well defined test environment.

Try to list all the boundaries of the problem domain. If there are too many, then consider the possibility that your problem is too broadly defined and needs to be broken down. What is the full set of necessary and sufficient conditions required to make your system pass all tests? Then look at every condition and treat it as an individual attack point. And list all the ways you can think of, of breaching that. Try to prove to yourself that you have found them all. Then write a test for each.

I would go through the above process first for the environment, build and test that first to a satisfactory standard and then for the more detailed logic within the workflow. Some iteration may be required if dependencies between the environment and the detailed logic occur to you during testing.

ReferenceURL : https://stackoverflow.com/questions/20265369/how-to-do-integration-testing-in-net-with-real-files

반응형

'code' 카테고리의 다른 글

컬렉션에 속성 설정-백본 JS  (0) 2020.12.31
PHP에 사전이 있습니까?  (0) 2020.12.31
Pthreads 대 OpenMP  (0) 2020.12.30
Razor의 ContentPlaceHolder?  (0) 2020.12.30
Django : 필드를 NULL로 설정하는 방법은 무엇입니까?  (0) 2020.12.30