Проблема с приведенным выше примером заключается в том, что метод parseFile
создает свой собственный экземпляр StreamReader
, поэтому насмешка над StreamReader
фактически не будет работать, потому что:
- У вас нет доступа к объекту.
- Вы можете издеваться только над
interfaces
или членами классов, помеченных как virtual
.
Вместо этого вы можете создать интерфейс, назовем его IFileManager
для аргументов, с помощью метода StreamReader
.
public interface IFileManager
{
StreamReader StreamReader(string path);
}
Затем в другом классе (назовем его Foo
), который содержит метод ParseFile
, который вы опубликовали выше:
public class Foo
{
IFileManager fileManager;
public Foo(IFileManager fileManager)
{
this.fileManager = fileManager;
}
public void parseFile(string filePath)
{
using (var reader = fileManager.StreamReader(filePath))
{
//Do something
}
}
}
Теперь вы можете смоделировать IFileManager
interface
и его метод StreamReader
, вы можете добавить этот смоделированный экземпляр в класс Foo
, сделав его доступным для использования методом ParseFile
.
Теперь ваш код будет зависеть от абстракции, в отличие от конкретной реализации, мы инвертировали зависимость, что позволяет нам имитировать зависимости и изолировать код, который мы хотим на самом деле протестировать.
Грубая демонстрация создания фиктивного объекта
public static void Main()
{
Mock<IFileManager> mockFileManager = new Mock<IFileManager>();
string fakeFileContents = "Hello world";
byte[] fakeFileBytes = Encoding.UTF8.GetBytes(fakeFileContents);
MemoryStream fakeMemoryStream = new MemoryStream(fakeFileBytes);
mockFileManager.Setup(fileManager => fileManager.StreamReader(It.IsAny<string>()))
.Returns(() => new StreamReader(fakeMemoryStream));
Foo foo = new Foo(mockFileManager.Object);
string result = foo.ParseFile("test.txt");
Console.WriteLine(result);
}
public interface IFileManager
{
StreamReader StreamReader(string path);
}
public class Foo
{
IFileManager fileManager;
public Foo(IFileManager fileManager)
{
this.fileManager = fileManager;
}
public string ParseFile(string filePath)
{
using (var reader = fileManager.StreamReader(filePath))
{
return reader.ReadToEnd();
}
}
}