2016-07-25 2 views
1

코딩 초보자입니다.유닛 테스트 C# 모의 인터페이스가 다른 인터페이스 안에 구성됨

public class A 
{ 
    public InterfaceB _b; 

    public A() 
    { 
     _b = new B(); 
    } 

    public string functionA() 
    { 
     if(String.IsNullOrEmpty(_b.GetId())) 
      return String.Empty; 
     else if(String.IsNullOrEmpty(_b.GetKey())) 
      return String.Empty; 
     else 
      return _b.GetToken(); 
    } 
} 

public interface InterfaceB 
{  
    string GetId(); 
    string GetKey(); 
    string GetToken(); 
} 

은 내가 interfaceB의 모든 세 가지 방법에 침투 할 수있는 functionA을 테스트 할 :

나는 클래스, A 있습니다. 내 단위 테스트에서는 클래스 A의 인스턴스를 만들고이를 호출 할 때 클래스 B의 동작을 설정할 수 없습니다.

데이터베이스를 계속 공격하지만 다른 테스트 케이스에서는 필요합니다.

어떻게 전체 논리를 테스트 할 수 있도록 완전히 모의합니까?

+0

, 당신은 직접 그 생성자에 조롱 개체'InterfaceB'를 전달하거나 설정할 수 있습니다 DI 검사를 사용하는 경우 주사를 위해서만 사용하십시오. – starlight54

답변

4

A 및 모의 인터페이스 InterfaceB을 테스트하려면 A을 작성하여 InterfaceB 인스턴스를 생성 할 필요가 없도록해야합니다. 대신 생성자를 통해 InterfaceB의 인스턴스를받습니다.

당신은 또 다시이 패턴을 볼 수 있습니다 :

public A() 
{ 
    private readonly InterfaceB _b; 

    public A(InterfaceB b) 
    { 
     _b = b; 
    } 

    public string functionA() 
    { 
     if(String.IsNullOrEmpty(_b.GetId())) return String.Empty; 
     else if(String.IsNullOrEmpty(_b.GetKey())) return String.Empty; 
     else return _b.GetToken(); 
    } 
} 

이것은 의존성 주입이라고합니다. 이는 클래스의 종속성이 클래스를 작성하는 클래스가 아니라 클래스에 "주입"된다는 것을 의미합니다. 이와 같이 생성자에 주입 할 때 "생성자 삽입"이라고도하지만 일반적으로 "종속성 주입"입니다. 그리고 당신이 물어 보는 것과 같은 인터페이스를 조롱 할 수 있다는 것이 왜 우리가 사용하는 이유 중 하나입니다.

몇 가지 중요한 세부 사항 :

  • InterfaceB 때문에 지금까지 A에, 생성자에게 아무것도 전달되지 실제 구현이 무엇인지를 "인식"합니다. 그것은 무엇이든 수 있습니다. 따라서 A은 결코 구체적인 구현에 묶여 있지 않습니다. 그래서 "모의"할 수 있습니다 InterfaceB.
  • 필드 _breadonly입니다. 이는 꼭 필요한 것은 아니지만 _b은 생성자에서만 설정할 수 있으며 다시 변경되지는 않습니다. 즉, A만이을 수신하고 사용합니다. 이 클래스는 결코 _b을 제어하지 않습니다. 이 무엇이든간에A은 그 값이 무엇인지 결정합니다. 이제

그 구현을 단위 테스트는

public class MockedInterfaceB : InterfaceB 
{ 
    private string _id; 
    private string _key; 
    private string _token; 

    public MockedInterfaceB(string id, string key, string token); 
    { 
     _id = id; 
     _key = key; 
     _token = token; 
    } 
    public string GetId() {return _id}; 
    public string GetKey() {return _key}; 
    public string GetToken() {return _token}; 
} 

처럼, 당신이 원하는 게 정확히 InterfaceB의 조롱 구현을 만들 수 있습니다 그리고 당신의 단위 테스트에 사용할 수있는 쓰고있어 :

var testA = new A(new MockedInterfaceB("myid","mykey","mytoken")); 

또한 Moq과 같은 도구를 사용하면 이러한 모의를 더 쉽게 만들 수 있습니다.

종속성 주입에 대해 듣는 경우 Castle Windsor, Autofac 또는 Unity 같은 종속성 주입 컨테이너의 컨텍스트에있는 경우가 많습니다. 그것들은 의존성 주입 작업을하도록 도와주는 유용한 도구입니다. 그들은 배울만한 가치가 있습니다.하지만 의존성 주입은 위의 예제에서 종속성 (InterfaceB)을 클래스 A에 "주입"하는 것과 같이 클래스를 작성하는 방법에 관한 것입니다.

+0

굉장한 스콧! ID, 키 및 토큰은 sql의 테이블 B에 있습니다. 빈, 0이 아닌 ID 및 0 ID와 같은 여러 시나리오를 시뮬레이트하고 싶습니다. 64bit keys .. 그러나 내가 의존성을 주입하고 소스 코드를 건드리지 않기를 원할 때 InterfaceB를 매개 변수로 사용하여 추가 생성자를 작성하고 싶지 않습니다. 또한 CI의 일부에서 확인하고 싶습니다. Moq를 사용할 때, 두 개의 분리 된 모의 객체 IA와 IB를 생성하고 B가 A?로 구성 될 때 기대를 설정하고 다른 하나에 moq를 삽입 할 수 있습니까? 그렇다면이를 달성하는 방법은 무엇입니까? – user2791094

+0

그런 종류의 하위 호환성이 필요한 경우 생성자 매개 변수를 선택적으로 만들고 기본값을 제공하십시오. 필요한 경우 테스트를 위해 클래스를 "수동으로"작성할 수 있습니다. 하나의 개체를 만들고 하나의 테스트를 위해 원하는 개체를 삽입하고 다른 테스트를 위해 다른 개체를 삽입하십시오. 테스트 객체를 작성하는 메소드를 작성할 수 있습니다. –

0

실제로는 Typemock을 사용하여 소스 코드를 변경하지 않고 테스트 할 수 있습니다. A의 인스턴스를 만들기 전에 B를 나중에 인스턴스로 모방 할 수 있습니다. 그런 다음 B의 메서드 동작을 수정할 수 있습니다. 예를 들어

: 당신은 매개 변수로`InterfaceB` 소요 A``에 생성자가 필요합니다

[TestMethod,Isolated] 
public void AllBMethodReturnStrings_WillReturnSuccess() 
{ 
    // Arrange 
    // Mocking future B's instance 
    var fakeIB = Isolate.Fake.NextInstance<B>(); 
    var realA = new A(); 

    Isolate.WhenCalled(()=> fakeIB.GetId()).WillReturn("fakeID"); 
    Isolate.WhenCalled(() => fakeIB.GetKey()).WillReturn("fakeKey"); 
    Isolate.WhenCalled(() => fakeIB.GetToken()).WillReturn("success"); 

    // Act 
    var result = realA.functionA(); 

    // Assert 
    Assert.AreEqual("success", result); 
} 
관련 문제