Что я обычно делаю, это создаю интерфейс для службы приложений, которая выполняет эту функцию. В моих примерах я предполагаю, что вы используете что-то вроде MVVM Toolkit или аналогичного (поэтому я могу получить базовую ViewModel и RelayCommand).
Вот пример чрезвычайно простого интерфейса для выполнения основных операций ввода-вывода, таких как OpenFileDialog и OpenFile. Я показываю их оба здесь, так что вы не думаете, что я предлагаю вам создать один интерфейс с одним методом, чтобы обойти эту проблему.
public interface IOService
{
string OpenFileDialog(string defaultPath);
//Other similar untestable IO operations
Stream OpenFile(string path);
}
В вашем приложении вы предоставляете реализацию этой службы по умолчанию. Вот как бы вы его потребляли.
public MyViewModel : ViewModel
{
private string _selectedPath;
public string SelectedPath
{
get { return _selectedPath; }
set { _selectedPath = value; OnPropertyChanged("SelectedPath"); }
}
private RelayCommand _openCommand;
public RelayCommand OpenCommand
{
//You know the drill.
...
}
private IOService _ioService;
public MyViewModel(IOService ioService)
{
_ioService = ioService;
OpenCommand = new RelayCommand(OpenFile);
}
private void OpenFile()
{
SelectedPath = _ioService.OpenFileDialog(@"c:\Where\My\File\Usually\Is.txt");
if(SelectedPath == null)
{
SelectedPath = string.Empty;
}
}
}
Так что все довольно просто. Теперь о последней части: тестируемость. Это должно быть очевидно, но я покажу вам, как сделать простой тест для этого. Я использую Moq для заглушки, но вы, конечно, можете использовать все, что захотите.
[Test]
public void OpenFileCommand_UserSelectsInvalidPath_SelectedPathSetToEmpty()
{
Mock<IOService> ioServiceStub = new Mock<IOService>();
//We use null to indicate invalid path in our implementation
ioServiceStub.Setup(ioServ => ioServ.OpenFileDialog(It.IsAny<string>()))
.Returns(null);
//Setup target and test
MyViewModel target = new MyViewModel(ioServiceStub.Object);
target.OpenCommand.Execute();
Assert.IsEqual(string.Empty, target.SelectedPath);
}
Это, вероятно, будет работать для вас.
В CodePlex есть библиотека под названием "SystemWrapper" (http://systemwrapper.codeplex.com), которая может избавить вас от необходимости делать лот такого рода вещи. Похоже, FileDialog не поддерживается тем не менее, вам определенно придется написать интерфейс для этого.
Надеюсь, это поможет.
Редактировать
Кажется, я помню, что вы предпочитали TypeMock Isolator для вашей фальшивой среды. Вот тот же тест с использованием Isolator:
[Test]
[Isolated]
public void OpenFileCommand_UserSelectsInvalidPath_SelectedPathSetToEmpty()
{
IOService ioServiceStub = Isolate.Fake.Instance<IOService>();
//Setup stub arrangements
Isolate.WhenCalled(() => ioServiceStub.OpenFileDialog("blah"))
.WasCalledWithAnyArguments()
.WillReturn(null);
//Setup target and test
MyViewModel target = new MyViewModel(ioServiceStub);
target.OpenCommand.Execute();
Assert.IsEqual(string.Empty, target.SelectedPath);
}
Надеюсь, это тоже полезно.