【问题标题】:How to unit test methods in windows form class?如何在 Windows 窗体类中对方法进行单元测试?
【发布时间】:2019-07-12 06:04:02
【问题描述】:

我正在开发一个 c# windows 窗体应用程序,并且我有一个存在于主窗体类中的方法。

把methodA想象成主表单类的一部分。

public void methodA() {
    A.someMethod();
    B.someMethod();

    // some more code

    if (someCondition) {
        // execute some code 
    }

    // initialize timer and set event handler for timer
    // run new thread 

    }

class A {
    someMethod() {...}
}

class B {
    someMethod() {...}
}

我将如何运行测试来测试此方法 A (isCondition) 的分支逻辑?因为它涉及初始化计时器和运行线程。我只能在进行系统测试时验证逻辑吗?我认为不可能模拟计时器和线程功能。

谢谢!

【问题讨论】:

    标签: c# visual-studio unit-testing integration-testing


    【解决方案1】:

    当然你可以模拟计时器。这是通过创建一个新接口,比如ITimerWrapper 并使用具体的 Timer 类来实现它。基本上是 Timer 类的包装器。然后使用它而不是您拥有的具体 Timer 类。

    以下内容:

    public partial class Form1 : Form
    {
        private readonly ITimerWrapper _timerWrapper;
        public Form1(ITimerWrapper timerWrapper)
        {
            InitializeComponent();
    
            this._timerWrapper = timerWrapper; // of course this is done via dependency injection
            this._timerWrapper.Interval = 1000;
        }
    
        private void Form1_Load(object sender, EventArgs e)
        {
            // now you can mock this interface
    
            this._timerWrapper.AddTickHandler(this.Tick_Event);
            this._timerWrapper.Start();
        }
    
        private void Tick_Event(object sender, EventArgs e)
        {
            Console.WriteLine("tick tock");
        }
    }
    
    public interface ITimerWrapper
    {
        void AddTickHandler(EventHandler eventHandler);
        void Start();
        void Stop();
        int Interval { get; set; }
    }
    public class TimerWrapper : ITimerWrapper
    {
        private readonly Timer _timer;
    
        public TimerWrapper()
        {
            this._timer = new Timer();
        }
    
        public int Interval
        {
            get
            {
                return this._timer.Interval;
            }
            set
            {
                this._timer.Interval = value;
            }
        }
    
        public void AddTickHandler(EventHandler eventHandler)
        {
            this._timer.Tick += eventHandler;
        }
    
        public void Start()
        {
            this._timer.Start();
        }
    
        public void Stop()
        {
            this._timer.Stop();
        }
    }
    

    然后对于新线程的旋转,也可以通过做同样的事情来测试。

    底线是有一个接口来分离关注点并在单元测试中模拟接口。

    【讨论】:

    • 在桥接接口背后的所有依赖项以启用 TDD 时,只有一件事需要注意。您最终将包装所有内容(DateTime、Environment、Timer、..),这会导致依赖项的高度复杂性。
    • 似乎所有的依赖都必须是接口类?
    • @dfhwze,它不会导致高复杂性,它会导致您使用的类/表单的明确且有据可查(可执行文档)的依赖关系。另一方面,UI(WindowsForms)可以被视为应用程序的入口点,并且可以/应该在不模拟依赖项的情况下进行测试。例如用于测试 Winforms 的框架:teststackwhite.readthedocs.io/en/latest/GettingStarted
    • @calveeen,不,只模拟使您的测试变慢的依赖项(数据库、文件系统、Web 服务)、设置非常非常复杂或不一致(时间相关)。
    猜你喜欢
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    • 2021-07-29
    • 1970-01-01
    相关资源
    最近更新 更多