如何以编程方式触发(密封)Windows窗体组件的事件?

时间:2022-11-24 20:06:39

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.

更具体一点:我想要一个单元测试来触发SaveFileDialog的FileOk事件,以便测试我自己的代码(包装SFD并在ShowDialog之前和之后做一些额外的事情)是否按预期工作。

Thanks in advance for any help on this.

在此先感谢任何帮助。

3 个解决方案

#1


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 :)

但是,在SaveFileDialog(或任何FileDialog)的情况下,OnFileOk受保护的方法将引发事件。您可以从SafeFileDialog派生并公开一个公共方法,它将调用OnFileOk或只使用反射调用OnFileOk。然后,它将调用FileOk的事件处理程序。我不确定我是否特别喜欢这些攻击计划中的任何一个,但是如果没有关于你想要做什么的更多信息,我想我只是回答这个问题而不是质疑太多:)


* 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.

*实际上,.NET本身确实有一个事件“加注”部分的想法,因此EventInfo.GetRaiseMethod。但是,这违背了IMO事件的一般概念,而C#编译器从不生成引发部分。我不相信标准库通常会暴露它。

#2


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.

如果在界面后面隐藏SaveFileDialog,则可以使用存根或模拟实现来测试代码。我不建议在单元测试中使用真实表单或控件,因为它们中的大多数都对活动消息循环具有硬依赖性。

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)
    {
        //...
    }
}

#3


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

我相信可以使用PrivateObject来调用类上的private / protected方法。

#1


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 :)

但是,在SaveFileDialog(或任何FileDialog)的情况下,OnFileOk受保护的方法将引发事件。您可以从SafeFileDialog派生并公开一个公共方法,它将调用OnFileOk或只使用反射调用OnFileOk。然后,它将调用FileOk的事件处理程序。我不确定我是否特别喜欢这些攻击计划中的任何一个,但是如果没有关于你想要做什么的更多信息,我想我只是回答这个问题而不是质疑太多:)


* 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.

*实际上,.NET本身确实有一个事件“加注”部分的想法,因此EventInfo.GetRaiseMethod。但是,这违背了IMO事件的一般概念,而C#编译器从不生成引发部分。我不相信标准库通常会暴露它。

#2


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.

如果在界面后面隐藏SaveFileDialog,则可以使用存根或模拟实现来测试代码。我不建议在单元测试中使用真实表单或控件,因为它们中的大多数都对活动消息循环具有硬依赖性。

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)
    {
        //...
    }
}

#3


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

我相信可以使用PrivateObject来调用类上的private / protected方法。