Reputation: 4738
I want to test a piece of code which returns an object.
I use NUnit and in a test class, I write a method to test if my method works fine...
[Test]
public void GetMyObjectFromLog()
{
string _xmlFilePath = @"C:\XmlFile.xml";
MyObjectParser _myObjectParser = new MyObjectParser();
MyObject _mockMyObject = new MyObject
{
Title = "obj",
Name = "objName"
}
MyObject _myObject = _myObjectParser.GetMyObjectFromLog(_xmlFilePath);
Assert.AreEqual(_mockMyObject , _myObject);
}
This test does not work because MyObject
does not override Equals
method, and I don't want to override Equals
method just for test purpose.
So I rewrite the test like this :
[Test]
public void GetMyObjectFromLog()
{
string _xmlFilePath = @"C:\XmlFile.xml";
MyObjectParser _myObjectParser = new MyObjectParser();
MyObject _myObject = _myObjectParser.GetMyObjectFromLog(_xmlFilePath);
Assert.AreEqual("obj", _myObject.Title);
Assert.AreEqual("objName", _myObject.Name);
}
Ok, it works... but is this test is pertinent ? Moreover, there is a dependance to a file.
Is it pertinent to use a Mock Framework instead of ? And how to use it ?
Thank you !
Upvotes: 7
Views: 194
Reputation: 8141
First of all, the method inside the parser should be name "Parse" instead of "Get".
Second of all, if you don't want the object itself to be able to compare itself to another, then it's perfectly fine to compare them just like you did (property by property). But this can be extracted into a helper method in the test class.
And lastly, you don't really want to tight-couple your parser with a file. You just want to parse text. If you want to include a static helper method that also opens a file and everything, that's your choice, but it shouldn't be a pure instance dependency.
[Test]
public void ParsesObjectFromXml()
{
string xmlInput = " ... ";
MyObjectXmlParser parser = new MyObjectXmlParser();
MyObject expected = new MyObject() {Title = "obj", Name="objName"};
AssertMyObjectsAreEqual(expected, parser.Parse(xmlInput));
}
private bool AssertMyObjectsAreEqual(MyObject expected, MyObject actual)
{
Assert.AreEqual(expected.Title, actual.Title);
Assert.AreEqual(expected.Name, actual.Name);
}
Now both your class and your test are clearer and only have a single responsibility.
Upvotes: 5
Reputation: 39339
About that dependency on the file (that even appears not to be in the project!):
You could override that _myObjectParser.GetMyObjectFromLog
to also accept a Stream. Then you can add that XML file as embedded resource and read it from the assembly.
Upvotes: 2
Reputation: 2709
The purpose of unit testing is to test the logic of the code, your test above is doing two things: 1. Logic 2. Search
I said search because you are trying to match an object that you created in an external file. If you do that the issue is your build will start to break if there is no external file present and you don't want that.
Solution: Create the file on the go but don't create a physical file, create a File in memory and then insert the object that you need to match, then match the object.
This way this test will never break.
Upvotes: 0
Reputation: 9424
Yes it looks ok like that. You could, however, override Equals
in your test project, if you don't need it in your main project. E.g. usually I create classes which promote private and protected classes to public ones. So you're free to extend your main project in order to simply testing in your test project.
A file dependency is ok, just put this file in your test suite project.
Upvotes: 1
Reputation: 1805
its absolutly ok to have a reference to a file. Generally there are two kinds of test types: unit tests and integration tests.
Integration tests are always interacting with some file / database or what ever. In your case you could improve the test by mocking the _myObjectParser.GetMyObjectFromLog.
You could either write the mock yourself or use a framework like rhinomocks. A very good book for nunit / rhinomocks is: The Art of Unit Testing.
A better testable version of GetMyObjectFromLog could look like this:
public MyObject GetMyObjectFromLog(IMyXmlReader reader)
{
var xmlData = reader.GetData();
//make your object here
var obj = new MyObject(xmlData);
return obj;
}
You can then implement 2 new classes that implemments a Interface IMyXmlReader, one that reads from a file for your productive code, and one that returns just always the same string on GetData().
You can then use your Class that returns always a static string for your unit tests.
Understand? Sorry for my english :)
Upvotes: 1