views:

430

answers:

3

To be more specific: I want a unit test to trigger SaveFileDialog's FileOk event in order to test whether my own code (which wraps SFD and does some additional things before and after ShowDialog) is working as intended.

Thanks in advance for any help on this.

A: 

If you hide the SaveFileDialog behind an interface, you can use a stub or mock implementation to test your code. I would not recommend using real forms or controls in unit tests, because most of them have a hard dependency on an active message loop.

public interface ISaveFileDialog
{
    event CancelEventHandler FileOk;
}

public class SaveFileDialogStub : ISaveFileDialog
{
    public event CancelEventHandler FileOk;

    public void RaiseFileOk(CancelEventArgs e)
    {
        FileOk(this, e);
    }
}

public class ClassUnderTest
{
    public ClassUnderTest(ISaveFileDialog dialog)
    {
        dialog.FileOk += OnFileOk;
    }

    void OnFileOk(object sender, CancelEventArgs e)
    {
        //...
    }
}
Jim Arnold
Hmmm - doing so would check my code, but not in combination with SFD. This would ensure that I pass the correct values to the dialog, but not whether these values are handled as intended by it. As SFD does quite some things under the hood, I'd prefer to actually save the file and check the location.
That's a different test altogether. For writing integration tests you probably want some kind of automation framework like White. The point I'm trying to make is that the internal implementation of SFD should have no bearing on your own code; if you don't trust SFD it's a different matter :)
Jim Arnold
...should have no bearing on *testing* your own code...
Jim Arnold
Hmm yeah I think you are right, it should not. SFD just fooled me once with weird behavior, and with all the options it has, I fear it will do so again next time I change any of its properties... That's why I thought it would be nice to include it into the test...
+1  A: 

The trouble is, events don't expose a "raise" operation* - they expose "subscribe" and "unsubscribe". It's up to the implementation how they implement subscribe/unsubscribe.

However, in the case of SaveFileDialog (or any FileDialog) there's the OnFileOk protected method which will raise the event. You could either derive from SafeFileDialog and expose a public method which will call OnFileOk or just call OnFileOk using reflection. That will then call the event handlers for FileOk. I'm not sure I particularly like either of these plans of attack, but without more information about what you're trying to do I thought I'd just answer the question instead of questioning too much :)


* In fact, .NET itself does have the idea of the "raise" part of an event, hence EventInfo.GetRaiseMethod. However, this goes against the general idea of an event IMO, and the C# compiler never generates the raise part. I don't believe the standard libraries usually expose it either.

Jon Skeet
Unfortunately, SFD ist sealed :-/ I would have preferred extension to wrapping anyway.The button class offers PerformClick(), thus the implementations seem to be slightly inconsistent in that point.Reflection is a good keyword, I'll try that (after all this would be more pragmatic...
... than an interfaces and two classes, only for the purpose of a single unit test. Maybe a good location for refactoring later on...)Thanks.
A: 

I believe it might be possible to use PrivateObject to invoke a private/protected method on your class.

davogones