1

I am writing a simple file converter which will take an XML file and convert it to CSV or vice-versa.

I have implemented 2 classes, XMLtoCSV and CSVtoXML and both implement a Convert method which takes the input file path and filter text and filters the XML by the given filter and performs the conversion. (e.g if the XML contains employee details, we might want to filter it so only employees from a certain department is retrieved and converted to CSV file).

I have a unit test which tests this Convert method. In it I am specifying the input file path and filter string and call the Convert function and assert the boolean result but I also need to test if the filtering worked and conversion has been completed.

My question is that do you really need to access the file IO and do the filtering and conversion via unit test? Is this not integration testing? If not then how can I assert the filtering has worked without actually converting the file and returning the results? I thought about Moq'ing the Convert method, but that will not necessarily prove that my Convert method is working fine.

Any help/advice is appreciated.

Thanks

2 Answers 2

4

I will suggest you to use streams in your classes and pass file stream in application and a "fake" or StringStream, for example, in unit tests. This will makes you more flexible in case you will decide to get this xml from WebService or any other way - you will just need to pass a stream, not file path.

Sign up to request clarification or add additional context in comments.

2 Comments

Or simply a string but streams are fine, too.
Streams may be better, because you can process data lazily (not wait until all chars are loaded)
2

My question is that do you really need to access the file IO and do the filtering and conversion via unit test? Is this not integration testing?

Precisely - in this case you are testing 3 things - the File IO system, the actual file contents, and the Convert method itself.

I think you need to look at restructuring your code to make it more amenable to unit testing (that's not a criticism of your code!). Consider your definition of the Convert method:

In it I am specifying the input file path and filter string

So your Convert method is actually doing two things - opening/reading a file, and converting the contents. You need to change things around so that the Convert method does one thing only - specifically, perform the conversion of a string (or indeed a stream) without having any reference to where it came from.

This way, you can correctly test the Convert method by supplying it with a string that you define yourself in your unit test - One test with known good data,and one with known bad data.

e.g.

void Convert_WithGoodInput_ReturnsTrue()
{
   var input="this is a piece of data I know is good and should pass";
   var sut = new Converter(); //or whatever it's called :)
   bool actual = sut.Convert(input);
   Assert.AreEqual(true,actual,"Convert failed to convert good data...");
}

void Convert_WithBadInput_ReturnsFalse()
{
   var input="this is a piece of data I know is BAD and should Fail. Bad Data! Bad!";
   var sut = new Converter(); //or whatever it's called :)
   bool actual = sut.Convert(input);
   Assert.AreEqual(false,actual,"Convert failed to complain about bad data...");
}

Of course inside your Convert method you are doing all sorts of arcane and wonderful things and at this point you might then look at that method and see if perhaps you can split it out into several internal methods, the functionality of which is perhaps provided by separate classes, which you provide as dependencies to the Converter class, and which in turn can all be tested in isolation.

By doing this you will be able to test both the functionality of the converter method, and you will be in a position to start using Mocks so that you can test the functional behaviour of it as well - such as ensuring that the frobber is called exactly once, and always before the gibber, and that the gibber always calls the munger, etc.

Bonus

But wait, there's more!!!!1!! - once your Converter class/method is arranged like this you will suddenly find that you can now implement an XML to Tab-delimited, or XML to JSON, or XML to ???? simply by writing the relevant component and plugging it into the Converter class. Loose coupling FTW!

e.g (and here I am just imagining how the guts of your convert function might work)

public class Converter
{
   public Converter(ISourceReader reader, IValidator validator, IFilter filter,IOutputformatter formatter)
   {
      //boring saving of dependencies to local privates here...
   }

   public bool Convert(string data,string filter)
   {
       if (!validator.Validate(data)) return false;
       var filtered = filter.Filter(data); 
       var raw = reader.Tokenise(filtered);
       var result = formatter.Format(raw);
       //and so on
       return true; //or whatever...
   }    
}

Of course I am not trying to tell you how to write your code but the above is a very testable class for both unit and functional testing, because you can mix and match Mocks, Stubs and Reals as and where you like.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.