Reputation: 12728
I'm working on an open source project with another developer. I am working on a unit test that needs to read in a default custom xml config file. I am only guaranteed that the part of the path that is in the repo will be on his machine. How can I rewrite this test to make it portable? I don't want tests to start failing every time we check the code into the repo.
public class ConfigurationTests
{
[TestMethod]
public void ConfigurationLoads()
{
//todo: how do I make this test portable?
const string configFile = @"C:\Users\Christopher\Source\Repos\RetailCoderVBE\RetailCoder.VBE\Config\rubberduck.config";
var deserializer = new XmlSerializer(typeof(Rubberduck.Config.Configuration));
using (StreamReader reader = new StreamReader(configFile))
{
Rubberduck.Config.Configuration config = (Rubberduck.Config.Configuration)deserializer.Deserialize(reader);
Assert.IsNotNull(config);
}
}
}
This is the part of the path that I am guaranteed the other dev will have. Everything before that I need to somehow dynamically get.
\RetailCoderVBE\RetailCoder.VBE\Config\rubberduck.config
Upvotes: 2
Views: 168
Reputation: 204
What you should do is create an interface to a file system and mock it in the test. The implementation of this interface which accesses the real file system you cannot test so it must be as simple as possible. Since XmlSerializer.Deserialize method accepts a Stream your interface can return a Stream.
public interface IFileAccess
{
Stream GetFileStream(string fileName);
}
public class RealFileAccess : IFileAccess
{
public Stream GetFileStream(string fileName)
{
....
}
}
public class ConfigLoader
{
Rubberduck.Config.Configuration LoadConfiguration(IFileAccess fileAccess)
{
const string configFile = @"C:\Users\Christopher\Source\Repos\RetailCoderVBE\RetailCoder.VBE\Config\rubberduck.config";
var deserializer = new XmlSerializer(typeof(Rubberduck.Config.Configuration));
return (Rubberduck.Config.Configuration)deserializer.Deserialize(fileAccess.GetFileStream(configFile));
}
}
And then the test would be
[TestMethod]
public void ConfigurationLoads()
{
const string configFile = @"C:\Users\Christopher\Source\Repos\RetailCoderVBE\RetailCoder.VBE\Config\rubberduck.config";
IFileAccess fileAccess = Mock.Of<IFileAccess>();
// setup fileAccess
Rubberduck.Config.Configuration config = new ConfigLoader().LoadConfiguration(fileAccess);
Assert.IsNotNull(config);
Mock.Get(fileAccess).Verify(fa => fa.GetFileStream(configFile));
}
You can then even check if GetFileStream was called with correct parameter.
Upvotes: 3
Reputation: 2468
I am working on a unit test that needs to read in a default custom xml config file.
Above strongly suggests it is not really unit-test. They're (ideally) independent from outer world. Why do you need to read the config file ? What information is stored in the config ? Perhaps it's possible to add a config file with dummy info to your project with tests OR stub the dependency to the file system with some interface.
A standard way to do so would look like
interface IConfigReader{
object GetValue(string key);
}
// later in code
var configDate = _reader.GetValue("ConnectionString");
Upvotes: 2