【发布时间】:2013-08-18 05:03:04
【问题描述】:
我有一个继承自抽象 Configuration 类的类,然后每个类实现 INI 文件、XML、conf 或专有格式的读取器。我在使用 FakeItEasy 创建要测试的对象时遇到问题。
我尝试测试的对象通过依赖注入使用配置对象,因此它可以通过调用 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 的不同调用的返回。
如何将参数的where和test这两种方法结合起来?
根据要求提供其他定义:
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();
}
}
【问题讨论】:
-
嗨,@Steven Scott。如果我们看到
IniReader的定义(至少是签名),我认为我们可以提供更好的帮助。听起来您正试图伪造一些非虚拟的方法 (which isn't supported)。如果没有伪造类的签名(以及表明哪一行引发异常),我们就无能为力了。 -
顺便说一句,也许我不应该混淆事物,但您的原始测试可能会更简单一些。你的第一个 A.CallTo 相当于
A.CallTo(() => FakeINI.ReadString("SignOn", "SendEnterClear")).Returns("N"); -
哦!我刚刚注意到别的东西。在
GetLoginSequence中,您有两个带有3 参数的ReadString 方法——看起来像一个部分、一个键和一个默认值。但是您的A.CallTos 仅指定 2 - 部分和键。我认为这不会导致您的“无法拦截非虚拟方法”。错误,但它会在某些时候导致错误,除了在您没有指定参数的最后一个示例中。但正如您所指出的,这不允许您为各种输入指定不同的返回类型。 -
@BlairConrad 感谢您的回复。实际上,INIReader 中的 ReadString 有各种选项,包括您指示的 3(Section, Key, Default)和 2 个参数(Section, Key),然后调用 3 参数 ReadString。
-
@BlairConrad 我认为你的定义不是虚拟的是正确的,但是我在父类中将它们定义为抽象,所以它们必须在继承类中定义并实现,然后这样做不允许我将虚拟方法添加到抽象定义中。我已将示例代码添加到主要问题中。
标签: c# testing ini fakeiteasy