I have a class that inherits from the abstract Configuration class, and then each class implements the reader for INI files, XML, conf, or proprietary formats. I am having a problem in creating the objects to be tested using FakeItEasy.
The object I am trying to test uses the configuration object via Dependency Injection, so it can simply read configuration settings by calling the ReadString(), ReadInteger() etc... functions, and then the text for the location (Section, Key for instance, with an INI) may be retrieved from the appropriate section in whatever format of configuration file (INI, XML, conf, etc...).
Sample code being used:
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;
}
A Simple Test example:
[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");
This compiles fine, but when I execute the code, I get the following Exception:
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.
If I change how I create the fake which then works without an exception, I can not get different values for the various calls to the same function.
A.CallTo(FakeINI).Where( x => x.Method.Name == "ReadString").WithReturnType<string>().Returns("N");
The above method does not allow me to control the return for the different calls that the function uses to the INI.
How can I combine the two methods, the where and the test of the parameters?
Additional definitions as requested:
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();
}
}
IniReader
. It sounds like you're trying to fake some methods that aren't virtual (which isn't supported). Without the signature of the class being faked (and an indication of which line throws the exception) there's not too much we can do. - Blair ConradA.CallTo(() => FakeINI.ReadString("SignOn", "SendEnterClear")).Returns("N");
- Blair ConradGetLoginSequence
, you have two ReadString methods that take 3 parameters - what look like a section, a key, and a default value. But yourA.CallTo
s only specify 2 - the section and key. I don't think that's causing your "Non virtual methods can not be intercepted." error, but it's going to cause an error at some point, except in your very last example where you don't specify the parameters. But as you point out, that doesn't allow you to specify the different return types for various inputs. - Blair Conrad