2014-03-19 44 views
1

我正在为使用MoQ进行嘲讽的现有代码库编写单元测试。单元测试受保护成员的命令

以下代码中的内容可能会引起混淆,但问题很简单。 我应该如何使用Moq访问受保护的CUT的模拟成员,或者是否有任何其他模拟框架允许我这样做? (而不必派生类,然后露出保护成员作为公众)

这是我的代码看起来像:

Class PageBase { 
    protected IController Controller; 
    public ICommand CloseCommand; 
} 

class PageDerived1 : PageBase { 

    protected void OnClosePage() 
    { 
     this.controller.ClosePage(); 
    } 
} 

现在,这已经长得难看。但是单元测试是通过在PageBase公众暴露命令有线的OnClosePage()方法,我做这样的事情

void TestPageDerived1PageCloseCommand { 
var pageDerived1 = new PageDerived1(); 
if (pageDerived1.CloseCommand.CanExecute()) { 
    pageDerived1.CloseCommand.Execute(); 
    // verify that the controller's ClosePage method was called, but how ? 
} 

正确的单元测试必须验证控制器的ClosePage命令调用。我打算使用模拟控制器来通知命令确实被调用。但是,控制器隐藏在PageDerived1类中。而且,由于它不适合公开这个控制器对象,因此它是没有意义的。我也不想为PageDerived1编写一个派生类来公开控制器,因为我将不得不为派生自PageBase的50个页面编写这个派生类。我讨厌它了。

由于提前, 镨

+0

我知道它不直接涉及到你的问题:你使用什么框架? –

+0

WPF,使用MVVM – PRE

+0

如果您使用WPF,那么您的所有控制器都是您自己的实现。它看起来像你的代码不太好测试。如果您测试所有公共方法,是不是所有方法都会被隐式测试? –

回答

1

您可以创建一个“通用”类公开暴露了一个IController属性,只需实例是在单元测试中通过指定导出的页面。

例子:

public class TestWrapperPage<TPage> : TPage 
    where TPage : PageBase 
{ 

    public void SetMyController(IController controller) 
    { 
     this.Controller = controller; 
    } 
} 

而且实例:

var page1 = new TestWrapperPage<PageDerived1>(); 
page1.SetMyController(mockController); 

var page2 = new TestWrapperPage<PageDerived2>(); 
page2.SetMyController(mockController); 

var page3 = new TestWrapperPage<PageDerived3>(); 
page3.SetMyController(mockController); 
// etc... 

虽然,上关的机会,你一个IController可以通过构造函数传入,没有需要上述。相反,只是通过你的模拟控制器通过构造函数:

var mockController = new Mock<IController>(); 
var pageBeingTested = new PageDerived1(mockController); 
+0

非常感谢BTownTKD ..我认为通用包装是我一直在寻找的。我完全忘了我也可以做到这一点。要回答你的第一个问题,控制器是通过构造函数设置的,但是由于它是一个受保护的属性,即使我设置了一个模拟控制器,它将如何提供帮助? – PRE

+0

我清理了答案,专注于看起来最合适的答案。但是,如果您能够将模拟控制器直接注入到所需页面类的构造函数中,那么您仍然可以监视模拟控制器的函数何时被调用。这将完全消除对包装类的需求。 – BTownTKD