【问题标题】:How to unit test OnPropertyChanged event handler in ViewModel如何在 ViewModel 中对 OnPropertyChanged 事件处理程序进行单元测试
【发布时间】:2014-10-29 15:28:32
【问题描述】:

我在单元测试视图模型方面遇到了以下问题。

在我的项目中,有多个视图模型(比如说 A、B、C 和 D)。 视图模型 A 是主视图模型,它处理来自视图模型 B、C 和 D 的 PropertyChanges,然后更新主视图。

视图模型 A 中的大多数方法/属性都是可单元测试的,除了处理来自 B、C 和 D 的 propertychanged 事件的事件处理程序方法。

例如:

public A()
{
  b.PropertyChanged += b_PropertyChanged;
  c.PropertyChanged += c_PropertyChanged;         
}


protected void b_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
  //process something based on the e.PropertyName 
  //might call some private or protected methods here to help with the processing
  switch(e.Property)
  {
     case "SearchResults":
        SearchResults = b.SearchResults;
        break;
  }   
}

如何在不公开的情况下测试 b_PropertyChanged?

【问题讨论】:

  • 更改bc 中的属性?有什么问题?
  • 您想准确测试什么?如果在视图模型 B 等中更改了特定属性,则视图模型 A 中的某些状态?如果 b_PropertyChanged 方法是公开的,请举例说明您的 Asserts 在单元测试中的内容。
  • 是 - A 将处理 B 或 C 中的任何属性更改
  • 好的 - 更新了代码以包含更多用于 b_PropertyChanged 的​​代码。在我的单元测试中,我会断言类似 SearchResults is not null

标签: c# wpf unit-testing mvvm


【解决方案1】:

您可以创建一个包装类来执行此操作(见下文),只需在其位置使用可测试类,它将执行代码。

public class Program
{
    private static void Main(string[] args)
    {
        TestableProgram2 tp = new TestableProgram2();
        tp.b_PropertyChanged(new Program(), "bang");
    }
}

public class Program2
{
    protected void b_PropertyChanged(object sender, string e)
    {
        Debug.Write(e);
    }
}

public class TestableProgram2 : Program2
{
    public new void b_PropertyChanged(object sender, string e)
    {
         e = "altered";       // here to demonstrate this code is entered.
        base.b_PropertyChanged(sender, e);
    }
}

【讨论】:

  • 那么,为测试目的创建该类的子类?
  • 是的,我以前必须这样做很多次,总是让我感到厌烦,但它确实有效。我只是稍作修改以使示例实际工作:) 你可以告诉它工作,因为调试将输出更改后的字符串,你可以将其删除,因为它只是在那里展示它通过公共方法到基础。跨度>
  • protected void b_PropertyChanged 应该是虚拟的吧?
  • 不,因为我们没有使用覆盖,我们从外部隐藏了方法,但在内部调用它。 (确保你使用的是我修改过的代码。如果你从内部调用一个方法,它需要是虚拟的,但是写它很酷(如果你调试并在e="altered" 上设置断点,它应该命中它然后调用基方法。如果我们使用覆盖并尝试更改可见性,您会收到编译器错误。
【解决方案2】:

在这些情况下,习惯上将功能从事件处理程序中移出并移到可以独立调用的自己的方法中。你可以试试这样的:

protected void b_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    YourNewMethod(e.Property);
}

public void YourNewMethod(string propertyName)
{
    switch(propertyName)
    {
       case "SearchResults":
          SearchResults = b.SearchResults;
          break;
    }   
}

在测试时,您现在可以致电YourNewMethod 来测试该功能。

【讨论】:

  • 好的 - 是否应该将 NewMethod 设置为 public 以便对其进行单元测试?
  • 您可以将其移出,但如果它受到保护,您仍然无法调用它,它必须是公开的,这不是很好。包装更干净,不涉及更改对象结构。这并不是说移出事件处理程序中的代码不是一个好主意:)
  • 是的,对不起...这是给你的复制和粘贴。 ;) 现已更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-01
相关资源
最近更新 更多