2017-11-26 26 views
2

AutoFixture 3.50 및 xUnit.NET을 사용하면 Fixture.Create()이 콘크리트 개체를 만드는 방식과 AutoData Theory가 콘크리트 개체를 만드는 방식간에 차이가있는 것으로 보입니다.AutoDataAttribute의 구체적인 개체 생성 논리가 모든 속성 가져 오기 도구를 한 번만 호출합니다

간단한 예 :

public class Foo 
{ 
    private string prop; 
    public string Prop 
    { 
     get 
     { 
      if (prop == null) { prop = "Prop"; } // Breakpoint 'A' 
      return prop; 
     } 
    } 
} 

테스트 Fixture 사용 :

[Fact] 
public void FixtureTest() 
{ 
    var fixture = new Fixture(); 
    var result = fixture.Create<Foo>(); // Breakpoint 'B1' 
} 

하여 시험 AutoDataAttribute :

[Theory, AutoData] 
public void AutoDataTest(Foo sut) 
{ 
    var bar = 1; // Essential no-op, Breakpoint 'B2' 
} 
,

이전 테스트에서 중단 점 'B1'은 중단 점 'A'가 적중되지 않는 동안 적중되었습니다. 후자의 테스트에서 중단 점 'A'는 중단 점 'B2'에 도달하기 전에 적중됩니다. 이것은 "지연"초기화 된 속성이 위와 비슷하지 않은 경우 문제가됩니다. 이는 테스트 실행 전에 속성의 배경 필드가 초기화 되었기 때문에 초기화 논리를 테스트 할 수 없기 때문입니다.

이 문제를 해결할 수 있도록 AutoDataAttribute을 사용자 정의하는 방법이 있습니까? 아니면 아마도 이것은 버그일까요?

답변

4

이것은 실제로 AutoFixture 문제가 아니라 오히려 xUnit.net 문제입니다. 이 같은 완전히 AutoFixture없이 재현 할 수 있습니다 :이 ClassDataTest으로 디버깅 할 경우

[Theory, ClassData(typeof(FooTestCases))] 
public void ClassDataTest(Foo sut) 
{ 
    var bar = 1; // Essential no-op, Breakpoint 'B3' 
} 

private class FooTestCases : IEnumerable<object[]> 
{ 
    public IEnumerator<object[]> GetEnumerator() 
    { 
     yield return new object[] { new Foo() }; 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 

, 당신은 또한 'A'당신이 중단 점을 명중하기 전에 'B3'를 중단 점에 있습니다.

xUnit.net 테스트 러너는 각 매개 변수화 된 테스트에 대해 적절한 표시 이름을 제공하므로 각 테스트 사례에 전달 된 모든 인수의 읽을 수있는 문자열 표현을 [Theory]에 작성하려고합니다.

데이터 개체가 명시 적으로 ToString을 덮어 쓰지 않으면 xUnit.net은 모든 속성을 읽고 해당 개체에서 표시 문자열을 작성합니다. 그것은 여기서 일어나는 일입니다.

나는 그 동작의 공식 문서를 찾으려고 노력했지만, 찾을 수 있었던 최선은 this입니다. 이 제안으로, 당신은 ToString를 재정 의하여 문제를 해결 얻을 수 있습니다 :

public class Foo 
{ 
    private string prop; 
    public string Prop 
    { 
     get 
     { 
      if (prop == null) { prop = "Prop"; } // Breakpoint 'A' 
      return prop; 
     } 
    } 

    public override string ToString() 
    { 
     return "Foo"; 
    } 
} 

이 변경 명중에서 브레이크 포인트 'A'를 중지 ClassDataAutoData을 사용하여 두 경우. ToString을 무시할지 여부는 또 다른 질문입니다. 당신이 FooToString을 무시하지 않으려면

, 아마 당신은 다음과 같이 ToString을 무시 않는 테스트 특정 자식 클래스를 테스트하여 문제를 해결 얻을 수 있습니다 :

[Theory, AutoData] 
public void AutoDataTestFoo(TestFoo sut) 
{ 
    var bar = 1; // Essential no-op, Breakpoint 'B4' 
} 

public class TestFoo : Foo 
{ 
    public override string ToString() 
    { 
     return "Foo"; 
    } 
} 

이 또한 중단 점을 중지 'A'가 맞지 않는다.

Foosealed이 아닌 한이 작업을 수행 할 수 있어야합니다.Foosealed 인 경우 FixtureTest 스타일로 테스트를 작성하는 것 이외의 다른 해결 방법은 생각할 수 없습니다.

+0

자세한 답변을 보내 주셔서 감사합니다. – MrPiao