I use moq 4.17.2 and FileSystem 17.0.3 for my tests.
For some reason, if the line (4) is included I always get null
whenever I call fileSystem.Object.Path.Combine
(e.g. in line (7)). But, when I remove line 4, then the Path.Combine
works as expected. What can be the problem?
1. var fileSystem = new Mock<FileSystem> { CallBase = true }.As<IFileSystem>();
2. dirInfo.ExistingFiles.ForEach(existingFile =>
3. {
4. fileSystem.Setup(fs => fs.Path.GetDirectoryName(existingFile)).Returns("");
5. fileSystem.Setup(fs => fs.File.Exists(existingFile)).Returns(true);
6. });
7. var path = fileSystem.Object.Path.Combine("a", "b");
df
CodePudding user response:
When you setup fs.Path.GetDirectoryName
MOQ will first auto-mock the Path
property recursively with a mocked IPath
and will thus return null
by default when you try to invoke a member that was not explicitly setup.
When you don't mock it the base class (FileSystem
) initializes a PathWrapper
implementation in its constructor and that is what is being invoked in your example when it behaves as you expected it.
/// <inheritdoc />
public FileSystem()
{
DriveInfo = new DriveInfoFactory(this);
DirectoryInfo = new DirectoryInfoFactory(this);
FileInfo = new FileInfoFactory(this);
Path = new PathWrapper(this);
File = new FileWrapper(this);
Directory = new DirectoryWrapper(this);
FileStream = new FileStreamFactory();
FileSystemWatcher = new FileSystemWatcherFactory();
}
In this case, how can I mock
GetDirectoryName
but make the rest methods of Path work with default implementation
Do the same for those properties like you did with FileSystem
and setup the members you want to override.
var fileSystem = new Mock<FileSystem> { CallBase = true }.As<IFileSystem>();
var pathWrapper = new Mock<PathWrapper>(fileSystem.Object);
pathWrapper.CallBase = true;
dirInfo.ExistingFiles.ForEach(existingFile => {
pathWrapper.Setup(p => p.GetDirectoryName(existingFile)).Returns("");
fileSystem.Setup(fs => fs.File.Exists(existingFile)).Returns(true);
});
fileSystem.Setup(fs => fs.Path).Returns(pathWrapper.Object);
var path = fileSystem.Object.Path.Combine("a", "b");