2014-05-09 3 views
0

Moq 및 Nunit을 사용하여 C# 코드의 단위 테스트를 수행하고 있으며 아래의 단순화 된 방법을 테스트하고 싶습니다. 단위 테스트 측면에서 보면 FooClass가 변경 될 수 있으며 이후에 내 테스트가 중단 될 수 있으므로 foo 값을 확인해서는 안됩니다. 그래서 내가 할 수있는 최소한은 모든 것이 초기화되고 제대로 호출되는지 확인하는 것입니다. 즉, someContainer가 올바른 값을 가져오고 FooClass가 someContainer를 가져오고 다른 일부 MyContainer 인스턴스는 가져 오지 않습니다. 어떻게해야합니까? 이 (단위) 테스트 접근법이 맞습니까?개체가 올바른 인수 값으로 인스턴스화되는지 테스트합니다.

public MyClass 
{ 
    ... 
    public bool MyMethod(int a, int b, int c, out FooClass foo) 
    { 
     var someContainer = new MyContainer{ 
     A = a, 
     B = b, 
     C = c 
     }; 

     foo = new FooClass(someContainer,1,2,3); 

     ... 
     return true; 
    } 
    ... 
} 

답변

2

방법 내부에서만 액세스 할 수 있습니다 someContainersomeContainer 때문에 당신은 foo 가져 것을 테스트 할 수 없습니다. 해당 방법에 대한 적절한 테스트는 fooa, bc의 올바른 위치에 있고 MyContainer 개체를 포함하는 것입니다. FooClass 개체에 올바른 MyContainer 개체가 포함되어 있는지 테스트 한 해당 FooClass 생성자의 단위 테스트입니다.

FooClass이 변경되면 아마도 MyMethod도 변경 될 것이므로 MyMethod의 테스트도 변경해야합니다. 테스트가 중단된다는 사실은 해당 메소드를 살펴보고 메소드가 원하는 것을 수행하고 원하는 것을 테스트하고 있다는 것을 의미하므로 바람직합니다. FooClass이 완료 될 때까지는 현재의 방법에 대해 적절한 테스트를 작성하거나 테스트를 전혀 작성하지 않아야합니다.

1

이 (단위) 테스트 방법이 맞습니까?

당신은 당신의 코드 (귀하의 예제에서 예를 들어 MyClass)의 특정 장치를 테스트 할 수 있도록 의존성을 조롱하고 싶은 경우에, 당신은 다른 돌봐 서비스로 코드를 작성 볼 필요가 책임. FooClass이 만들어되어야한다는 MyContainer 인스턴스를 제공하는 새로운 FooClass

  • 만들기 새로운 MyContainer
  • 만들기

    1. : 당신의 예에서 당신의 MyMethod 여러 가지 책임이 있습니다.

  • MyMethod가에 특정 MyContainer을 전달하는 테스트 당신의 욕망을 충족하려면 FooClass 새로운 클래스로 밖으로 책임 (1)과 (2)를 분리 할 수 ​​있습니다. 일반적으로 C#에서는이 클래스에 인터페이스를 제공하고 MyClass은 이러한 각 인터페이스를 종속성으로 사용합니다. 예 :

    public interface IFooClassProvider 
    { 
        FooClass CreateFooClass(MyContainer container, int d, int e, int f); 
    } 
    
    public interface IMyContainerProvider 
    { 
        MyContainer CreateMyContainer(int a, int b, int c); 
    } 
    
    public MyClass 
    { 
        private IMyContainerProvider _myContainerProvider; 
        private IFooClassProvider _fooClassProvider; 
    
        public MyClass(IMyContainerProvider myContainerProvider, IFooClassProvider fooClassProvider) 
        { 
         _myContainerProvider = myContainerProvider; 
         _fooClassProvider = fooClassProvider; 
        } 
        ... 
        public bool MyMethod(int a, int b, int c, out FooClass foo) 
        { 
         var someContainer = _myContainerProvider.CreateMyContainer(a,b,c); 
    
         foo = _fooClassProvider.CreateFooClass(someContainer,1,2,3); 
    
         ... 
         return true; 
        } 
        ... 
    } 
    

    인터페이스의 '실제'구현이 명확하게 이루어지기를 바랍니다. 테스트를 수행하기 위해 이러한 인터페이스 각각에 대한 모의 작업을 만들 수 있습니다 (예 : new Mock<IFooclassProvider>()을 찾아 MyClass의 생성자로 전달합니다. 유닛 테스트에서는 SetupIMyContainerProvider 유닛 테스트에서 생성 한 특정 컨테이너 인스턴스를 제공자에게 조롱 할 수 있습니다. 그런 다음 IFooClassProvider mock의 메소드가 특정 컨테이너와 함께 호출 된 Verify을 사용할 수 있습니다.

    예.

    var mockFooClassProvider = new Mock<IFooClassProvider>(); 
    var mockMyContainerProvider = new Mock<MyContainerProvider>(); 
    
    var myKnownContainer = new MyContainer(...); 
    mockMyContainerProvider.Setup(m => m.CreateMyContainer(It.IsAny<int>, ...)) 
        .Returns(myKnownContainer); 
    
    var myClass = new MyClass(mockMyContainerProvider.Object, mockFooClassProvider.Object); 
    
    FooClass fooClass; 
    myClass.MyMethod(..., out fooClass); 
    
    mockFooClassProvider.Verify(m => m.CreateFooClass(myKnownContainer, It.IsAny<int>(),...); 
    

    이 답변은 간단한 상황에 극단적으로 일을 가지고,하지만 난 문제의 예를 좀 더 복잡한 코드의 단순화 된 버전이었다 그림. 이러한 방식으로 책임을 분리하면 코드를 짧은 테스트 가능한 세그먼트로 신속하게 단순화 할 수 있습니다.

    관련 문제