TDD测试重构以支持MultiThreading

前端之家收集整理的这篇文章主要介绍了TDD测试重构以支持MultiThreading前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
所以我是TDD的新手,我使用MVP模式成功创建了一个不错的小样本应用程序.我当前解决方案的主要问题是它阻止了UI线程,所以我试图设置Presenter以使用SynchronizationContext.Current,但是当我运行我的测试时,SynchronizationContext.Current为null.

演讲者在线程之前

  1. public class FtpPresenter : IFtpPresenter
  2. {
  3. ...
  4. void _view_GetFilesClicked(object sender,EventArgs e)
  5. {
  6. _view.StatusMessage = Messages.Loading;
  7.  
  8. try
  9. {
  10. var settings = new FtpAuthenticationSettings()
  11. {
  12. Site = _view.FtpSite,Username = _view.FtpUsername,Password = _view.FtpPassword
  13. };
  14. var files = _ftpService.GetFiles(settings);
  15.  
  16. _view.FilesDataSource = files;
  17. _view.StatusMessage = Messages.Done;
  18. }
  19. catch (Exception ex)
  20. {
  21. _view.StatusMessage = ex.Message;
  22. }
  23. }
  24. ...
  25. }

线程前测试

  1. [TestMethod]
  2. public void Can_Get_Files()
  3. {
  4. var view = new FakeFtpView();
  5. var presenter = new FtpPresenter(view,new FakeFtpService(),new FakeFileValidator());
  6.  
  7. view.GetFiles();
  8. Assert.AreEqual(Messages.Done,view.StatusMessage);
  9. }

现在,我向Presenter添加了SynchronizationContext线程后,我尝试在我的Fake View上为StatusMessage设置AutoResetEvent,但是当我运行测试时,SynchronizationContext.Current为null.我意识到我在新的Presenter中使用的线程模型并不完美,但这是测试多线程的正确技巧吗?为什么我的SynchronizationContext.Current为null?我该怎么做呢?

线程后的演示者

  1. public class FtpPresenter : IFtpPresenter
  2. {
  3. ...
  4. void _view_GetFilesClicked(object sender,Password = _view.FtpPassword
  5. };
  6. // Wrap the GetFiles in a ThreadStart
  7. var syncContext = SynchronizationContext.Current;
  8. new Thread(new ThreadStart(delegate
  9. {
  10. var files = _ftpService.GetFiles(settings);
  11. syncContext.Send(delegate
  12. {
  13. _view.FilesDataSource = files;
  14. _view.StatusMessage = Messages.Done;
  15. },null);
  16. })).Start();
  17. }
  18. catch (Exception ex)
  19. {
  20. _view.StatusMessage = ex.Message;
  21. }
  22. }
  23. ...
  24. }

线程测试

  1. [TestMethod]
  2. public void Can_Get_Files()
  3. {
  4. var view = new FakeFtpView();
  5. var presenter = new FtpPresenter(view,new FakeFileValidator());
  6.  
  7. view.GetFiles();
  8. view.GetFilesWait.WaitOne();
  9. Assert.AreEqual(Messages.Done,view.StatusMessage);
  10. }

假视图

  1. public class FakeFtpView : IFtpView
  2. {
  3. ...
  4. public AutoResetEvent GetFilesWait = new AutoResetEvent(false);
  5. public event EventHandler GetFilesClicked = delegate { };
  6. public void GetFiles()
  7. {
  8. GetFilesClicked(this,EventArgs.Empty);
  9. }
  10. ...
  11. private List<string> _statusHistory = new List<string>();
  12. public List<string> StatusMessageHistory
  13. {
  14. get { return _statusHistory; }
  15. }
  16. public string StatusMessage
  17. {
  18. get
  19. {
  20. return _statusHistory.LastOrDefault();
  21. }
  22. set
  23. {
  24. _statusHistory.Add(value);
  25. if (value != Messages.Loading)
  26. GetFilesWait.Set();
  27. }
  28. }
  29. ...
  30. }
我遇到了与ASP.NET MVC类似的问题,它缺少HttpContext.您可以做的一件事是提供一个替代构造函数,允许您注入模拟SynchronizationContext或公开执行相同操作的公共setter.如果无法在内部更改SynchronizationContext,则在默认构造函数中创建一个设置为SynchronizationContext.Current的属性,并在整个代码中使用该属性.在备用构造函数中,您可以将模拟上下文分配给属性 – 或者如果您为其提供公共setter,则可以直接为其分配.

公共类FtpPresenter:IFtpPresenter
{
public SynchronizationContext CurrentContext {get;组; }

  1. public FtpPresenter() : this(null) { }
  2.  
  3. public FtpPresenter( SynchronizationContext context )
  4. {
  5. this.CurrentContext = context ?? SynchronizationContext.Current;
  6. }
  7.  
  8. void _view_GetFilesClicked(object sender,EventArgs e)
  9. {
  10. ....
  11. new Thread(new ThreadStart(delegate
  12. {
  13. var files = _ftpService.GetFiles(settings);
  14. this.CurrentContext.Send(delegate
  15. {
  16. _view.FilesDataSource = files;
  17. _view.StatusMessage = Messages.Done;
  18. },null);
  19. })).Start();
  20.  
  21. ...
  22. }

我要做的另一个观察是,我可能让你的演示者依赖于Thread类的接口,而不是直接在Thread上.我不认为您的单元测试应该创建新线程,而是与模拟类进行交互,以确保调用创建线程的正确方法.您也可以注入该依赖项.

如果在调用构造函数时SynchronizationContext.Current不存在,则可能需要将赋值逻辑移动到Current并进入延迟加载.

猜你在找的设计模式相关文章