What you are missing is the inverse of the control. For example, you can introduce the principle of entering dependencies in your code:
public interface IXmlDataProviderFactory { XmlDataProvider Create(string fileName); } public class LocalizationData { private IXmlDataProviderFactory factory; public LocalizationData(IXmlDataProviderFactory factory) { this.factory = factory; } private bool IsValidFileName(string fileName) { return fileName.ToLower().EndsWith("xml"); } public XmlDataProvider LoadFile(string fileName) { if (IsValidFileName(fileName)) { XmlDataProvider provider = this.factory.Create(fileName); provider.IsAsynchronous = false; return provider; } return null; } }
In the above code, XmlDataProvider creation XmlDataProvider abstracted using the IXmlDataProviderFactory interface. An implementation of this interface can be provided in the LocalizationData constructor. Now you can write your unit test as follows:
[Test] public void LoadFile_DataLoaded_Succefully() { // Arrange var expectedProvider = new XmlDataProvider(); string validFileName = CreateValidFileName(); var data = CreateNewLocalizationData(expectedProvider); // Act var actualProvider = data.LoadFile(validFileName); // Assert Assert.AreEqual(expectedProvider, actualProvider); } private static LocalizationData CreateNewLocalizationData( XmlDataProvider expectedProvider) { return new LocalizationData(FakeXmlDataProviderFactory() { ProviderToReturn = expectedProvider }); } private static string CreateValidFileName() { return "d:/azeri.xml"; }
FakeXmlDataProviderFactory as follows:
class FakeXmlDataProviderFactory : IXmlDataProviderFactory { public XmlDataProvider ProviderToReturn { get; set; } public XmlDataProvider Create(string fileName) { return this.ProviderToReturn; } }
Now in a test environment, you can (and probably should) always create a class under the test manually. However, you want to distract the creation in factory methods so that you cannot change many tests when the class under the test changes.
In your work environment, however, this can become very cumbersome very soon when you need to manually create a class. Especially when it contains a lot of dependencies. This is where the IoC / DI frameworks shine. They can help you with this. For example, if you want to use LocalizationData in your production code, you can write code like this:
var localizer = ServiceLocator.Current.GetInstance<LocalizationData>(); var data = data.LoadFile(fileName);
Please note that as an example, I am using the Common Service Locator .
The structure will take care of creating this instance for you. However, using such an dependency injection infrastructure, you will need to tell the infrastructure which “services” you need. For example, when I use the Simple Service Locator library as an example (headless plugin), your configuration might look like this:
var container = new SimpleServiceLocator(); container.RegisterSingle<IXmlDataProviderFactory>( new ProductionXmlDataProviderFactory()); ServiceLocator.SetLocatorProvider(() => container);
This code is usually included in the path to launch your application. Of course, the only missing piece of the puzzle is the real ProductionXmlDataProviderFactory class. Here he is:
class ProductionXmlDataProviderFactory : IXmlDataProviderFactory { public XmlDataProvider Create(string fileName) { return new XmlDataProvider { Source = new Uri(fileName, UriKind.Absolute) }; } }
It also does not follow that you probably do not want to inject your LocalizationData into your production code yourself, because this class is probably used by other classes that depend on this type. What you usually do is ask the framework to create the topmost class for you (for example, a command that implements the full use case) and execute it.
Hope this helps.