C# 我是否应该将 windows 表单事件相关的私有函数 public 仅用于测试目的?

C# Shall I make my windows form event related private functions public just for testing purpose?

这可能是一个非常普遍的问题,关于如何对 windows 表单应用程序和异步函数进行单元测试。

我正在为一个 windows 表单应用程序编写单元测试用例,该应用程序到处都有异步功能。

我有所有的事件处理函数,例如按钮点击事件函数,私有的。我需要测试这些功能,但我不能直接在外部调用这些功能来测试它们。

我试图通过调用 PerformClick() 从单元测试代码中触发事件函数。它适用于通用函数,但不适用于异步函数,因为我认为 PeformClick() 不会等待并且我无法在测试代码中验证结果。

这是我的代码的一个简单示例。我们有两种布局结构。表格class只有表格设计。 Form Presenter 来保存函数的所有逻辑。我需要在 Presenter class.

中测试 BtnApplyChangeClick 函数
public interface IStandForm
{
    Control.ControllCollections controls {get;}
}
public partial class Form1 : Form, IStandardForm
{
   public Form1()
   {
        InitializeComponent(); // It has a button called BtnDelete
   }
   public Control.ControlCollection controls
   {
        return this.Controls;
   }
}

public class FormPresenter
{   
    IStandardForm myForm;
    IDBController dbController;
    public FormPresenter(IStandardForm form, IDBController dbController)
    {
       this.myForm = form;
       this.dbController = dbController;

       //Assign the event to the button
       Button BtnDelete= (Button)myForm.Controls["BtnDelete"];
       BtnDelete.Click += new System.EventHandler(BtnDeleteClick);
    }

    private async void BtnDeleteClick(object sender, EventArgs e)
    {
        //some validation code   

       //Call db delete
        await dbController.Delete();  
    }
}

//Test Code
[TestFixture]
public class TestFormLogin
{
    [Test]
    public async Task Delete_With_Exception()
    {            
        Mock<IDbController> mockDbController = new Mock<IDbController>();
        mockDbController.Setup(c => c.Delete()).ThrowAsync<Exception>(new Exception("Test Exception"));
        IStandardForm myForm = new Form1;

        FormPresenter = new FormPresenter(mockDbController.Object, myForm);
        Button BtnDelete=(Button)myForm.Controls["BtnDelete"];

        Action act = () => BtnDelete.PerformClick();

        //This assertion will be failed as PeformClick won't wait
        act.Should().Throw<Exception>();  
    }
}

最后一行异常断言不起作用。如果我可以调用事件处理程序函数 BtnDeleteClick,断言就可以了。

仅仅为了测试目的而将私有事件处理函数设为 public 是不是一个坏主意?它会让我的生活更轻松,但听起来没有意义。

Would that be a bad idea to just simply make the private event handler function to be public just for testing purpose? It will make my life easier but doesn't sound make sense.

您想调查 "ports and adapters" a.k.a。 "hexagonal architecture"。这个想法是您使用您的应用程序,并从应用程序的角度定义它需要的接口。这包括 UI 的接口,双向通信。

一旦您将整个 UI 置于抽象之后,您就可以编写带有存根实现的单元测试,这些存根实现充当伪造的 UI。