I am working on a tool that loads assemblies using Mono.Cecil. I have the following Factory that returns an object named binary and depends on interface responsible for loading assemblies with AssemblyDefinintion.ReadAssembly
method.
I am completely new to unit testing and I need to unit test the GetBinary
method.
internal sealed class DotNetBinaryFactory : IBinaryFactory
{
private readonly IBinaryLoader binaryLoader;
public DotNetBinaryFactory(IBinaryLoader binaryLoader)
{
this.binaryLoader = binaryLoader;
}
[NotNull] public Binary GetBinary([NotNull] FilePath path)
{
var assembly = binaryLoader.LoadBinary(path);
return BinaryUtils.GetBinary(assembly);
}
}
Here is the IBinaryLoader
dependency implementation
internal interface IBinaryLoader
{
AssemblyDefinition LoadBinary(FilePath path);
}
internal sealed class DotnetBinaryLoader : IBinaryLoader
{
public AssemblyDefinition LoadBinary([NotNull] FilePath path)
{
try
{
return AssemblyDefinition.ReadAssembly(path.Path);
}
catch (Exception)
{
Console.WriteLine("Exception in loading Assembly From : " + path.Path);
throw;
}
}
}
So to unit test GetBinary
method I need to mock IBinaryLoader
and setup LoadBinary
method to return a dummy AssemblyDefinition
object, but I can't create one.
Here is what I tried
[Test]
public void GetDotnetBinary_AssemblyDefinitionInput_ReturnCorrectDotnetFrameworkBianry()
{
var path = FilePath.GetRandom();
var mockedAssemblyDef = new Mock<AssemblyDefinition>();
var binaryLoader = new Mock<IBinaryLoader>();
binaryLoader.Setup(m => m.LoadBinary(path)).Returns(mockedAssemblyDef.Object);
}
You need to create mocks of services, not of data. In your case AssemblyDefinition
is data, and is sealed
as well. Mocks aren't meant for concrete data classes. Your mock of the "service" binaryLoader
looks ok.
What you need to do instead is create your dummy AssemblyDefinition
another way, and return that. I'm not familiar with Mono.Cecil, but it looks like there is a static Create() method you could use. Once you've got that instance you need, the rest of your test should fall into place.
You'll end up with something like
[Test]
public void GetDotnetBinary_AssemblyDefinitionInput_ReturnCorrectDotnetFrameworkBianry()
{
// arrange
var path = FilePath.GetRandom();
var assemblyDef = AssemblyDefinition.Create(...); // or however your create a real one
var binaryLoader = new Mock<IBinaryLoader>();
binaryLoader.Setup(m => m.LoadBinary(path)).Returns(assemblyDef);
var factory = new DotNetBinaryFactory(binaryLoader);
// act
var result = factory.GetBinary(path);
// assert
// your assertions here...
}
I see also that your types are internal. Assuming your tests are in a different assembly, you will have to make the internals visible to that assembly. This is done by putting an [InternalsVisibleTo] attribute in the source assembly.