I am new to mocking and trying out moq for the first time. I am wondering if I can write a test only using mocks?
public class FileCopierTests
{
private string path = AppDomain.CurrentDomain.BaseDirectory;
[Fact]
public void Copy_starts_copying_when_event_is_fired_returns_true()
{
var fullyQualifiedFileName = string.Format(@"{0}\..\..\Integration\TestData.xls", this.path);
var destFileName = Path.GetTempPath() + "66768c06-d1c4-4416-be81-767f36abeeb1.xls";
var copierMock = new Mock<IFileCopier>();
var watcherMock = new Mock<IFileWatcher>();
copierMock.Setup(cp => cp.Copy(fullyQualifiedFileName, destFileName)).Raises(
ev => ev.CopyingFinished += null, destFileName);
watcherMock.Object.Changed += arg => copierMock.Object.Copy(arg, destFileName);
watcherMock.Raise(e => e.Changed += null, fullyQualifiedFileName);
copierMock.VerifyAll();
}
}
These are the classes and interfaces I want to test,
public interface IFileCopier
{
event Action<string> CopyingFinished;
void Copy(string fqFileName, string destFileName);
}
public class FileCopier : IFileCopier
{
private ReaderWriterLockSlim @lock = new ReaderWriterLockSlim();
public event Action<string> CopyingFinished;
public void Copy(string fqFileName, string destFileName)
{
this.@lock.EnterWriteLock();
try
{
File.Copy(fqFileName, destFileName, true);
if (this.CopyingFinished == null)
{
return;
}
this.CopyingFinished(destFileName);
}
finally
{
this.@lock.ExitWriteLock();
}
}
}
public interface IFileWatcher
{
event Action<string> Changed;
}
public class FileChangeWatcher : IFileWatcher
{
public FileChangeWatcher(FileSystemWatcher eyes)
{
this.Eyes = eyes;
this.Eyes.Changed += this.OnChangedEvent;
}
protected FileSystemWatcher Eyes { get; set; }
public event Action<string> Changed;
private void OnChangedEvent(object sender, FileSystemEventArgs eventArgs)
{
if (this.Changed == null)
{
return;
}
this.Changed(eventArgs.FullPath);
}
}
What you are doing isn’t correct – when you write a test using only mocks you aren’t really testing anything!
Instead what you want is to introduce some of your non mocked code, code that uses the objects that you are replacing with mocks.
Two of the big things that using mocks (and in particular mocking frameworks like moq) gives you is:
1 – Isolation
2 – Verifiability
By isolation I mean that in your case you don’t want to really copy a file every time you test actions on your file copier class. So you replace the real file copier with something that pretends to be the file copier.
By verifiability I mean that often classes don’t have any way to tell you if they were called. This is usually a good thing since telling other people if they have been called isn’t part of their job, but in testing scenarios you want this information – the expectations in moq allow you to gather it.
In this case it looks like you have something which raises an event, and then something that listens for this event and calls the copy method on your FileCopier.
So you want to mock out the event source (or call the concrete source of the event in the right way) and then make that event be raised.
You then need a second mock – the mock of the FileCopier that has an expectation that its copy method will be called with the correct parameters. This FileCopier mock should be being passed to the class that calls it (Dependency Injection) and this the allows you to confirm that the copy method is called by your real code.