9

I am trying to write a unit test that covers the following line

var fileFullName = fileInfo.FullName;

where fileInfo is an instance of FileInfo.

I am using fakes to shim the FileInfo object, but I am unable to provide a value for the FullName property, because it is inherited from the base class.

For the Name property, which is not inherited, I can simply do this:

ShimFileInfo.AllInstances.NameGet = info => OriginalFullName;

The answer provided by Microsoft is to create the shim on the base class, in this case FileSystemInfo. But if I try this:

ShimFileSystemInfo.AllInstances.FullNameGet = info => OriginalFullName;

It does not work, because FileSystemInfo is an abstract class which cannot be created and therefore cannot be shimmed.

In this particular case, I can get around it because I can combine the DirectoryName and Name properties to make it testable, but it seems crazy that I can't just use the property I want because it happens to come from the base.

Has anyone come accross this problem and managed to solve it?

SerG
  • 1,251
  • 4
  • 18
  • 37
lextechnica
  • 103
  • 2
  • 6
  • Well, I haven't come across this problem, but what about using Reflection? – Tony Vitabile Apr 09 '14 at 12:31
  • Why not just create a test file? Is there any particular reason why you want to use fakes when a test file will do? – gfish3000 Apr 09 '14 at 12:32
  • Consider what you actually want to test, if you are not using a test file then what is actually under test here? It looks like you are going in a direction were all you will be testing are your fakes. – Zache Apr 09 '14 at 13:04
  • @Zache: This sounds like an attempt to isolate logic from filesystem logic for the sake of a unit test, which would be corrupted (made not unit) if an actual file is involved. Even so, the use of shims may indicate a refactor point. If the logic in question doesn't *need* a FileInfo instance, just a couple of strings, it might be better to pass those in. – Magus Apr 09 '14 at 14:20
  • I have refactored out the logic which actually interacts with the file system into a helper class and put an interface on it so that it can be mocked in the unit tests for any other class which uses it. However, the helper class itself needs unit tests for complete code coverage and therefore fakes must be used to Shim the File system operations – lextechnica Apr 10 '14 at 10:23

1 Answers1

5

You said that shimming the base class didn't work, but I do exactly that and it works in our tests.

FileInfo in System.dll is defined as FileInfo : FileSystemInfo, and FileSystemInfo is in mscorlib. Many types in mscorlib are not shimmed by default, but if you add this to your mscorlib.fakes file:

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
  <Assembly Name="mscorlib" Version="4.0.0.0"/>
  <ShimGeneration>
    <Add FullName="System.IO.FileSystemInfo"/>
  </ShimGeneration>
</Fakes>

and then build your test project you get a ShimFileSystemInfo for FileSystemInfo from mscorlib, as well as the ShimFileInfo for FileInfo from System.dll. Then this works:

using (ShimsContext.Create())
{
    var directoryName = "<testPath>";
    var fileName = "test.txt";
    ShimFileSystemInfo.AllInstances.FullNameGet = @this => "42";
    result = new DirectoryInfo(directoryName).GetFiles(fileName).First();
    Assert.AreEqual("42", result.FullName);   // the fake fullname
    Assert.AreEqual("test.txt", result.Name); // the real name
}

Caveat: works on my machine (Visual Studio 2013, .NET 4.5.1)

Reference for the fakes file: Code generation, compilation, and naming conventions in Microsoft Fakes

Andy Brown
  • 18,961
  • 3
  • 52
  • 62
  • The extra piece inside the mscorlib.fakes did the trick here too. It also serve as an example for everything that is not generated out of the box, which makes sense. – Dorival Feb 03 '15 at 20:54