2009-10-21 5 views
2

저와 함께 있으니, NUnit을 처음 접하겠습니다. 나는 Rails의 땅에서 왔습니다. 그래서이 중 일부는 저에게 새로운 것입니다.NUnit 모의가 싱글 톤 방식에서 작동하지 않습니다.

나는 다음과 같은 코드 행이 :

var code = WebSiteConfiguration.Instance.getCodeByCodeNameAndType("CATALOG_Brands_MinQty", item.Catalog); 

내가 (이미 초기화 code 가정)과 같이, 그것을 조롱하기 위해 노력하고있어 :

var _websiteConfigurationMock = new DynamicMock(typeof(WebSiteConfiguration)); 
_websiteConfigurationMock.ExpectAndReturn("getCodeByCodeNameAndType", code); 

언제 디버그 테스트 getCodeByCodeNameAndTypenull 인 경우 예상되는 code 대신에 반환됩니다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

NUnit과 버전 : 2.2.8

답변

1

DynamicMock는 조롱하려는 클래스 (MarshalByRef에서 상속) 인터페이스, 또는 marshallable을 나타내는 메모리 새로운 객체를 생성합니다.

이 시도 : WebSiteConfiguration이 MarshalByRef에서 상속하지 않는 세 번째 줄이 작동하지 않습니다

var _websiteConfigurationMock = new DynamicMock(typeof(WebSiteConfiguration)); 
_websiteConfigurationMock.ExpectAndReturn("getCodeByCodeNameAndType", code); 
WebSiteConfiguration conf = (WebSiteConfiguration)_websiteConfigurationMock.MockInstance; 
var x = conf.getCodeByCodeNameAndType("CATALOG_Brands_MinQty", item.Catalog); 

참고.

당신이 일반적으로하는 일은 인터페이스를 모의하고이 인터페이스를 구현하는 새로운 객체를 얻는 것이지만, 구체적인 유형을 만들어야 할 필요없이 구성한 방식대로 동작합니다. TypeMock과 같은 더 나은 격리 프레임 워크를 사용하지 않으면 기존 객체의 정적 메서드/속성에 대한 호출을 가로 채기 만하면됩니다.

7

미안하지만 나는 NUnit.Mocks를 한번도 사용하지 못했습니다.하지만 NMock 및 Moq [내가 추천하는 바]에 대한 경험이 있습니다. 일반적으로 조롱 라이브러리를 사용하여 인터페이스 정의에 대한 프록시를 생성하고 NUnit.Mocks가 같은 방식으로 작동한다고 가정합니다. 당신이 싱글을 조롱하려는 경우

따라서, 당신은 가능성이, 다음을 수행 할 수

있을 것이다. 인터페이스를 만듭니다 (예 :

).
// All methods you would like to mock from this class, should 
// be members of this interface 
public interface IWebSiteConfiguration 
{ 
    // Should match signature of method you are mocking 
    CodeType getCodeByCodeNameAndType (
     string codeString, 
     CatalogType catalogType); 
} 

b. "구현"인터페이스

// You've already written the method, interface matches signature, 
// should be as easy as slapping interface on class declaration 
public class WebSiteConfiguration : IWebSiteConfiguration { } 

c. 인터페이스를 사용하십시오.

괜찮므로 단계 c. 너의 일의 대부분이 어디있을거야. 논리적으로, 만약 당신이 싱글 톤을 조롱하고 있다면, 당신은 실제로 당신이 샘플을 버리지 않은 소비자를 테스트하는 것입니다. c. 단순히 소비자의 매개 변수에 매개 변수를 추가하거나 'IWebSiteConfiguration'유형의 공개적으로 액세스 가능한 속성을 추가 한 다음 내부적으로 인스턴스 멤버를 참조하고이 새 인터페이스에 대해 메서드를 호출하면됩니다.

public class MyClass 
{ 
    public MyClass() { } 

    public void DoSomething() 
    { 
     // bad singleton! bad boy! static references are bad! you 
     // can't change them! convenient but bad! 
     code = WebSiteConfiguration.Instance.getCodeByCodeNameAndType (
      "some.string", 
      someCatalog) 
    } 
} 

했다, 이것을 고려하면, 모의을 만들 소비자에게 조롱의 참조를 전달하고, 소비자를 테스트, 당신의 단위 테스트에서

public class MyClass 
{ 
    private readonly IWebSiteConfiguration _config = null; 

    // just so you don't break any other code, you can default 
    // to your static singleton on a default ctor 
    public MyClass() : this (WebSiteConfiguration.Instance) { } 

    // new constructor permits you to swap in any implementation 
    // including your mock! 
    public MyClass (IWebSiteConfiguration config) 
    { 
     _config = config; 
    } 

    public void DoSomething() 
    { 
     // huzzah! 
     code = _config.getCodeByCodeNameAndType ("some.string", someCatalog) 
    } 
} 

된다.

[Test] 
public void Test() 
{ 
    IWebSiteConfiguration mockConfig = null; 
    // setup mock instance and expectation via 
    // NUnit.Mocks, NMock, or Moq 

    MyClass myClass = new MyClass (mockConfig); 
    myClass.DoSomething(); 

    // verify results 
} 

이 또한 사출 [DI]을 의존성 실용적인 소개로서 기능한다. 소비자가 서비스를 직접 호출하는 것보다는 (예 : 정적 싱글 톤 클래스를 통해) 서비스 참조 (예 : 웹 사이트 구성 클래스)를 소비자에게 전달하거나 "주입"하는 것입니다.

희망이 도움이 :)

+0

이것이 식욕을 자극한다면, 더 읽을 거리가있는 몇 가지 빠른 참조. 마틴 의존성 삽입 (Dependency Injection)에 파울러 [DI], 제어 [IOC의]의 반전, 및 컨테이너 성 윈저 컨테이너 [HTTP에 [http://martinfowler.com/articles/injection.html] 빠른 튜토리얼 : // dotnetslackers. co.kr/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart1.aspx] –

1

가이 사용하는 반사에 대한 솔루션의 일종이다, 또는 어쩌면 나는 완전히이 오해 보인다.

는 여기에 설명되어 있습니다 : http://www.geekbeing.com/2010/05/23/how-to-unit-test-singleton-hack-in-c

그것이 정말 일 수 있을까? SingletonClass 개인 생성자를 가질 것이기 때문에 https://github.com/rbabreu/TestableSingleton

public class TestableSingleton : SingletonClass 
{ 
    public TestableSingleton() 
    { 
    FieldInfo fieldInfo = typeof(SingletonClass) 
     .GetField("_instance", 
     BindingFlags.Static | BindingFlags.NonPublic); 
    fieldInfo.SetValue(Instance, this); 
    } 
} 

프로젝트 availabe는 사실은 내가 비주얼 스튜디오에서 컴파일 할 수 없었다. 누군가가 작동하도록하면 어댑터 패턴의 오버 헤드를 피하는 것이 좋습니다.