2013-08-15 9 views
1

나는 추상적 인 구성 클래스로부터 상속받은 클래스를 가지고 있으며, 각 클래스는 INI 파일, XML, conf 또는 독점적 형식에 대한 독자를 구현합니다. FakeItEasy를 사용하여 테스트 할 개체를 만드는 데 문제가 있습니다.C#에서 FakeItEasy로 INI 구성 파일 설정 위조하기

내가 테스트하려고하는 객체는 Dependency Injection을 통해 구성 객체를 사용하므로 ReadString(), ReadInteger() 등의 함수를 호출 한 다음 구성 설정을 읽을 수 있습니다. 섹션, 예를 들어, 키, INI 포함)는 구성 파일 (INI, XML, conf ... 등)의 형식에 관계없이 적절한 섹션에서 검색 할 수 있습니다.

샘플 코드를 사용 :

public class TestFile 
{ 
    private readonly ConfigurationSettings ConfigurationController_ ; 

    ... 

    public TestFile(ConfigurationSettings ConfigObject) 
    { 
     this.ConfigurationController_ = ConfigObject; 
    } 

    public TestFile(XMLFile ConfigObject) 
    { 
     this.ConfigurationController_ = ConfigObject; 
    } 

    public TestFile(INIFile ConfigObject) 
    { 
     this.ConfigurationController_ = ConfigObject; 
    } 

    ... 

    private List<string> GetLoginSequence() 
    { 
     List<string> ReturnText = new List<string>(); 
     string SignOnFirst = ConfigurationController_.ReadString("SignOn", "SignOnKeyFirst", "Y"); 
     string SendEnterClear = ConfigurationController_.ReadString("SignOn", "SendEnterClear", "N"); 

     if (SendEnterClear.Equals("Y", StringComparison.CurrentCultureIgnoreCase)) 
     { 
      ReturnText.Add("enter"); 
      ReturnText.Add("clear"); 
     } 

     if (SignOnFirst.Equals("N", StringComparison.CurrentCultureIgnoreCase)) 
     { 
      ReturnText.AddRange(MacroUserPassword("[$PASS]")); 
      ReturnText.Add("sign_on"); 
     } 
     else 
     { 
      ReturnText.Add("sign_on"); 
      ReturnText.AddRange(MacroUserId("[$USER]")); 
      ReturnText.AddRange(MacroUserPassword("[$PASS]")); 
     } 
     return ReturnText; 
    } 

간단한 시험 예 :

[TestMethod] 
    public void TestSignOnSequence() 

     IniReader FakeINI = A.Fake<IniReader>(); 

     //Sample Reads: 
     //Config.ReadString("SignOn", "SignOnKeyFirst", "Y"); 
     //Config.ReadString("SignOn", "SendEnterClear", "N"); // Section, Key, Default 

     A.CallTo(() => FakeINI.ReadString(A<string>.That.Matches(s => s == "SignOn"), A<string>.That.Matches(s => s == "SendEnterClear"))).Returns("N"); 
     A.CallTo(() => FakeINI.ReadString(A<string>.That.Matches(s => s == "SignOn"), A<string>.That.Matches(s => s == "SignOnKeyFirst"))).Returns("N"); 

     A.CallTo(FakeINI).Where(x => x.Method.Name == "ReadInteger").WithReturnType<int>().Returns(1000); 

     TestFile TestFileObject = new TestFile(FakeINI); 

     List<string> ReturnedKeys = TestFileObject.GetLoginSequence(); 
     Assert.AreEqual(2, ReturnedKeys.Count, "Ensure all keystrokes are returned"); 

이 잘 컴파일,하지만 난 코드를 실행할 때, 나는 다음과 같은 예외 얻을 :

Test threw Exception: 
FakeItEasy.Configuration.FakeConfigurationException: 
    The current proxy generator can not intercept the specified method for the following reason: 
    - Non virtual methods can not be intercepted. 

예외없이 작동하는 가짜를 어떻게 변경하면, 다른 값을 얻을 수 없습니다. 동일한 기능에 대한 다양한 호출.

A.CallTo(FakeINI).Where(x => x.Method.Name == "ReadString").WithReturnType<string>().Returns("N"); 

위의 방법으로는 함수가 INI에 사용하는 다른 호출에 대한 리턴을 제어 할 수 없습니다.

매개 변수의 위치와 테스트의 두 가지 방법을 결합하려면 어떻게해야합니까? 요청에 따라

추가 정의 :

public abstract class ConfigurationSettings 
{ 
    ... 

    abstract public int ReadInteger(string Section, string Key, int Default); 
    abstract public string ReadString(string Section, string Key, string Default); 

    public int ReadInteger(string Section, string Key) 
    { return ReadInteger(Section, Key, 0); } 

    public int ReadInteger(string Key, int Default) 
    { return ReadInteger("", Key, Default); } 

    public int ReadInteger(string Key) 
    { return ReadInteger(Key, 0);    } 

    public string ReadString(string Section, string Key) 
    { return ReadString(Section, Key, null); } 
} 

public class IniReader : ConfigurationSettings 
{ 
    ... 

    public IniReader() 
    { 
    } 

    public IniReader(string PathAndFile) 
    { 
     this.PathAndFileName = PathAndFile; 
    } 

    public override int ReadInteger(string Section, string Key, int Default) 
    { 
     return GetPrivateProfileInt(Section, Key, Default, PathAndFileName); 
    } 

    public override string ReadString(string Section, string Key, string Default) 
    { 
     StringBuilder WorkingString = new StringBuilder(MAX_ENTRY); 
     int Return = GetPrivateProfileString(Section, Key, Default, WorkingString, MAX_ENTRY, PathAndFileName); 
     return WorkingString.ToString(); 
    } 
} 
+0

안녕, @Steven 스콧. 'IniReader'의 정의 (적어도 서명)를 보았다면 좀 더 잘 할 수있을 것이라고 생각합니다. 가상이 아닌 ([지원되지 않는]) (https://github.com/FakeItEasy/FakeItEasy/wiki/What-can-be-faked) 몇 가지 방법을 위조하려고하는 것 같습니다. 위조 된 클래스의 서명없이 (그리고 어떤 라인이 예외를 던지는지에 대한 표시없이) 우리가 할 수있는 것이 너무 많지 않습니다. –

+0

제쳐두고, 어쩌면 내가 혼동해서는 안되지만 원래의 테스트는 조금 더 간단 할 수 있습니다. 첫 번째 A.CallTo는 과 같습니다. A.CallTo (() => FakeINI.ReadString ("SignOn", "SendEnterClear")) 반환 값 : " –

+0

OH! 방금 다른 걸 눈치 챘어. 'GetLoginSequence'에는 섹션, 키 및 기본값과 같은 _3_ 매개 변수를 취하는 두 개의 ReadString 메서드가 있습니다. 그러나 A.CallTo는 섹션과 키만 2로 지정합니다. 나는 그것이 당신의 "가상이 아닌 방법들이 가로 챌 수 없다"는 것을 생각하지 않는다. 오류가 발생하지만 매개 변수를 지정하지 않은 마지막 예제를 제외하고는 오류가 발생할 수 있습니다. 그러나 여러분이 지적한대로, 다양한 입력에 대해 서로 다른 리턴 타입을 지정할 수는 없습니다. –

답변

2

다음과 같은 이유에 대해 지정된 방법 가로 챌 수

현재 프록시 생성기를 얻고 : 를 - 비 가상의 방법이 될 수 없다 도청.

오류는 가짜 ReadString의 2 매개 변수 버전을 시도하고 있기 때문이다. Only virtual members, abstract members, or interface members can be faked. 귀하의 두 개의 paremter ReadString이 이들 중 어느 것도 아니기 때문에 위조 될 수 없습니다. 나는 당신이 가상의 2 매개 변수 ReadString 또는 가짜 3 매개 변수 ReadString 중 하나를 가져야한다고 생각합니다.

예를 들어, GetLoginSequence에서 3 매개 변수 ReadString을 사용하고 있기 때문에 특히 유용합니다. 그렇다면 메서드 이름 스트링 대신에 표현식을 사용하는 것을 제약 할 수 있다고 생각합니다.

나는 (대부분 사용자의 갱신 전에서) 코드의 비트와 약간의 테스트를 만들어 3 매개 변수 ReadString을 날조 성공했다 :

[Test] 
public void BlairTest() 
{ 
    IniReader FakeINI = A.Fake<IniReader>(); 

    A.CallTo(() => FakeINI.ReadString("SignOn", "SendEnterClear", A<string>._)).Returns("N"); 
    A.CallTo(() => FakeINI.ReadString("SignOn", "SignOnKeyFirst", A<string>._)).Returns("N"); 

    // Personally, I'd use the above syntax for this one too, but I didn't 
    // want to muck too much. 
    A.CallTo(FakeINI).Where(x => x.Method.Name == "ReadInteger").WithReturnType<int>().Returns(1000); 


    TestFile TestFileObject = new TestFile(FakeINI); 

    List<string> ReturnedKeys = TestFileObject.GetLoginSequence(); 
    Assert.AreEqual(2, ReturnedKeys.Count, "Ensure all keystrokes are returned"); 
} 
+1

감사합니다. 당신의 방향에 따라 코드에서 더 열심히 보았고 추상과 가상의 차이를 보았을 때 가상을 사용할 수도있었습니다. 그러나 추가 매개 변수를 지정하면 매력처럼 작동합니다. 도와 주셔서 대단히 감사합니다. –