I have a Transfer
class, simplified it looks like this:
public class Transfer { public virtual IFileConnection source { get; set; } public virtual IFileConnection destination { get; set; } public virtual void GetFile(IFileConnection connection, string remoteFilename, string localFilename) { connection.Get(remoteFilename, localFilename); } public virtual void PutFile(IFileConnection connection, string localFilename, string remoteFilename) { connection.Get(remoteFilename, localFilename); } public virtual void TransferFiles(string sourceName, string destName) { source = internalConfig.GetFileConnection("source"); destination = internalConfig.GetFileConnection("destination"); var tempName = Path.GetTempFileName(); GetFile(source, sourceName, tempName); PutFile(destination, tempName, destName); } }
The simplified version of the IFileConnection
interface looks like this:
public interface IFileConnection { void Get(string remoteFileName, string localFileName); void Put(string localFileName, string remoteFileName); }
The real class is supposed to handle a System.IO.IOException
that is thrown when the IFileConnection
concrete classes loses connectivity with the remote, sending out emails and what not.
I would like to use Moq to create a Transfer
class, and use it as my concrete Transfer
class in all properties and methods, except when the GetFile
method is invoked - then I want it to throw a System.IO.IOException
and make sure the Transfer
class handles it properly.
Am I using the right tool for the job? Am I going about this the right way? And how would I write the setup for that unit test for NUnit
?
To streamline the configuration of methods throwing exceptions, Moq has special constructs targeting this scenario: Throws and ThrowsAsync . Both methods accept an instance of any Exception type. . ThrowsAsync(new Exception("My custom exception"));
Mock is a method/object that simulates the behavior of a real method/object in controlled ways. Mock objects are used in unit testing. Often a method under a test calls other external services or methods within it. These are called dependencies.
What happens when you mock something? First of all, we should define what a mock is: In a unit test, mock objects can simulate the behavior of complex, real objects and are therefore useful when it is impractical or impossible to incorporate a real object into a unit test. Mocking makes sense in a unit testing context.
Mockito verify() method can be used to test number of method invocations too. We can test exact number of times, at least once, at least, at most number of invocation times for a mocked method. We can use verifyNoMoreInteractions() after all the verify() method calls to make sure everything is verified.
Here's how you can mock your FileConnection
Mock<IFileConnection> fileConnection = new Mock<IFileConnection>( MockBehavior.Strict); fileConnection.Setup(item => item.Get(It.IsAny<string>,It.IsAny<string>)) .Throws(new IOException());
Then instantiate your Transfer class and use the mock in your method call
Transfer transfer = new Transfer(); transfer.GetFile(fileConnection.Object, someRemoteFilename, someLocalFileName);
Update:
First of all you have to mock your dependencies only, not the class you are testing(Transfer class in this case). Stating those dependencies in your constructor make it easy to see what services your class needs to work. It also makes it possible to replace them with fakes when you are writing your unit tests. At the moment it's impossible to replace those properties with fakes.
Since you are setting those properties using another dependency, I would write it like this:
public class Transfer { public Transfer(IInternalConfig internalConfig) { source = internalConfig.GetFileConnection("source"); destination = internalConfig.GetFileConnection("destination"); } //you should consider making these private or protected fields public virtual IFileConnection source { get; set; } public virtual IFileConnection destination { get; set; } public virtual void GetFile(IFileConnection connection, string remoteFilename, string localFilename) { connection.Get(remoteFilename, localFilename); } public virtual void PutFile(IFileConnection connection, string localFilename, string remoteFilename) { connection.Get(remoteFilename, localFilename); } public virtual void TransferFiles(string sourceName, string destName) { var tempName = Path.GetTempFileName(); GetFile(source, sourceName, tempName); PutFile(destination, tempName, destName); } }
This way you can mock internalConfig and make it return IFileConnection mocks that does what you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With