views:

49

answers:

2

I have a Silverlight testing project using the Silverlight Unit Test Framework.

I want to test a method in my view model which takes FileInfo objects. This seems to work fine when I test it manually through the UI.

Now I want a unit test just for the AddDocument method. I don't want to test actually clicking the button or simulate clicking a button - I just want to test that the AddDocument method.

Here's the code behind from the view. The mySessionViewModel object is in the DataContext. The method I want to test is mySessionViewModel.AddDocument();

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    OpenFileDialog openFileDialog1 = new OpenFileDialog();

    openFileDialog1.Filter = 
        "Text Files (.txt)|*.txt|All Files (*.*)|*.*";
    openFileDialog1.FilterIndex = 1;

    openFileDialog1.Multiselect = true;

    bool? userClickedOK = openFileDialog1.ShowDialog();

    if (userClickedOK == true)
    {
        IList<FileInfo> files = new List<FileInfo>();
        foreach (FileInfo file in openFileDialog1.Files)
        {
            mySessionViewModel.AddDocument(file);
        }
    } 
}

I put some test files in a subdirectory of the web project and tried this, but it throws a SecurityException consistent with Silverlight's security model:

SessionView sessionViewModel = new SessionViewModel();

DirectoryInfo di = new DirectoryInfo("testFiles");
var files = di.EnumerateFiles();
foreach (var file in files)
{
    sessionViewModel.AddDocument(file);
}

// assert some stuff
+2  A: 

The Silverlight security model will not allow file access unless it is via the file open dialog (this is for in browser).

Further, the file open dialog can of course only be fired from a user interface event (mouse click etc).

The ability to read external files is not really something that should need automated testing. A single interactive UI test would have proved that one.

For automated testing, to test the processing logic of your files, you could use files internal to the test project e.g. referenced as resources.

Enough already
+2  A: 

The main problem here is you want to Unit Test a method that takes a FileInfo as a parameter. However there is no automated way to create an instance of FileInfo.

Hence to unit test this method you should consider changing the type of the parameter. Its quite likely that the internals of this method only access a handful of the properties and methods on the FileInfo. Hence create an interface that represents those members and change the method to use the interface rather than the FileInfo directly.

Now you can create a wrapper class for FileInfo that implements the interface and you can also create another class for use in unit testing that implements the same interface but gets its content elsewhere.

AnthonyWJones
Anthony thanks. I tried using the FileStream type as a parameter instead if FileInfo - I want to read the file. Silverlight documentation says you can access filesystem using this (with limitations, eg path not visible). But still get SecurityException.
Nick Miller
@Nick Miller: Try using a more basic *Stream* as the parameter type and have the test provide ResourceStream's
Enough already
@Nick: You can only do that if the `FileInfo` is provided by `OpenFileDialog`. Besides, passing in a stream places the burden of opening and disposing the stream on the calling code which is not a good choice just to support testing. I would still go with a wrapper even if it only has an `OpenRead` method. Now you might choose to have that `OpenRead` return a `Stream` if your code will work with that. If not use `FileStream` but your mock wrapper will need to use an `IsolatedStorageFileStream` (with `Stream` you also have the option of using a `StreamResourceInfo.Stream`).
AnthonyWJones