2013-10-24 61 views
2

我想测试一个将ViewModel作为参数的帮助器方法。我遇到的问题是,测试似乎需要我实例化并分配我的ViewModel使用的所有模型。在我给出的例子中,这不是什么大不了的,因为只有少数几个,但是在我工作的实际虚拟机上有一吨。有没有其他的方式来做到这一点,所以我不必创建和分配每个对象?出于说明的目的如何对ViewModel使用方法进行单元测试?

实施例的代码...

模型

public class Meal 
{ 
    public int MealID { get; set; } 

    public string Title { get; set; } 
    public decimal Cost { get; set; } 
} 

public class Beverage 
{ 
    public int BeverageID { get; set; } 

    public string Title { get; set; } 
    public decimal Cost { get; set; } 
} 

public class Desert 
{ 
    public int DesertID { get; set; } 

    public string Title { get; set; } 
    public decimal Cost { get; set; } 
} 

的视图模型

public class DinnerViewModel 
{ 
    public Meal Meal { get; set; } 
    public Beverage Beverage { get; set; } 
    public Desert Desert { get; set; } 

    public decimal SalesTax { get; set; } 
    public bool SeniorDiscount { get; set; } 
} 

辅助

public class Calculator 
{ 
    public decimal Total(DinnerViewModel dvm) 
    { 
     decimal subtotal = dvm.Meal.Cost + dvm.Beverage.Cost + dvm.Desert.Cost; 

     if (dvm.SeniorDiscount) 
     { 
      subtotal = subtotal - (subtotal * 0.1M); 
     } 

     return subtotal + (subtotal * dvm.SalesTax); 
    } 
} 

测试

[TestMethod] 
public void CalculatorReturnsCorrectTotalForNonSenior() 
{ 
    DinnerViewModel dvm = new DinnerViewModel(); 
    dvm.Meal.Cost = 7M; 
    dvm.Beverage.Cost = 1M; 
    dvm.Desert.Cost = 2M; 
    dvm.SalesTax = 0.08M; 
    dvm.SeniorDiscount = false; 

    Calculator calc = new Calculator(); 

    decimal expected = 10.80M; 
    decimal actual = calc.Total(dvm); 

    Assert.AreEqual(expected, actual, "The actual value does not match the expected value."); 
} 

这将导致一个 “NullReferenceException” 错误。正如我所说的,我可以创建并分配必要的对象...

[...] 
Meal meal = new Meal(); 
dvm.Meal = meal; 
dvm.Meal.Cost = 7M; 
[...] 

...而且,一旦他们完成所有操作,测试成功,但是这似乎是一个更大的虚拟机大量的工作我觉得有一些事情我可以做,让这更容易。

回答

2

您看到NullReferenceException,因为在实例化时,Meal,Beverage和Desert实例未分配给DinnerViewModel的相应属性。所以,所有这些属性都是null。您应该在访问这些属性之前创建并分配新对象。您可以使用视图模型的构造:

public class DinnerViewModel 
{ 
    public DinnerViewModel() 
    { 
     Meal = new Meal(); 
     Beverage = new Beverage(); 
     Desert = new Desert(); 
    } 

    public Meal Meal { get; set; } 
    public Beverage Beverage { get; set; } 
    public Desert Desert { get; set; } 

    public decimal SalesTax { get; set; } 
    public bool SeniorDiscount { get; set; } 
} 

而且我喜欢创造一些辅助方法,返回存根测试。它消除了重复,使你的测试明确:

private DinnerViewModel CreateTenDollarsDinner() 
{ 
    return new DinnerViewModel { 
     Meal = new Meal { Cost = 7M }, 
     Beverage = new Beverage { Cost = 1M }, 
     Desert = new Desert { Cost = 2M }, 
     SalesTax = 0.08M, 
     SeniorDiscount = false 
    }; 
} 

[TestMethod] 
public void CalculatorReturnsCorrectTotalForNonSenior() 
{ 
    DinnerViewModel dvm = CreateTenDollarsDinner();  
    Calculator calc = new Calculator(); 
    Assert.AreEqual(10.80M, calc.Total(dvm)); 
} 
+1

这个问题解决了!谢谢一堆! – Jason

+0

我确定了另一件我在做错的事情,这在我的示例代码中并不明显。当一个模型有一个像'public int AnotherModelID {get;组; }'和一个像'public virtual AnotherModel AnotherModel {get;组; }',例如,在View中可以访问像'vm.Model.AnotherModel.Property'这样的属性,但是在测试时它似乎不起作用。除了在构造函数中实例化模型之外,我还必须将模型添加到VM中,如'AnotherModel AnotherModel = new AnotherModel();' – Jason

0

无论你的模型(膳食,Beaverage和甜品)是的ViewModels过,或者你DinnerViewModel是不是一个真正的视图模型。

ViewModel的目的是为View提供直接可用的值。

根据您的单元测试例如,它会更合适,直接把你的Calculator.Total helper方法的DinnerViewModel和揭露计算出的总价值为属性的观点:

public class DinerViewModel 
{ 
    public Meal Meal { get; set; } 
    public Beverage Beverage { get; set; } 
    public Desert Desert { get; set; } 

    public decimal SalesTax { get; set; } 
    public bool SeniorDiscount { get; set; } 

    public decimal TotalCostOfDinner 
    { 
     get 
     { 
      decimal subtotal = 0M; 
      if(Meal != null) subtotal += Meal.Cost; 
      if(Beverage != null) subtotal += Beverage.Cost; 
      if(Desert != null) subtotal += Desert.Cost; 

      if (SeniorDiscount) subtotal -= subtotal * 0.1M; 

      return subtotal + (subtotal * SalesTax); 
     } 
    } 
} 

现在您查看可以直接从DinnerViewModel中获取正确的TotalCostOfDinner。

现在的单元测试:

[TestMethod] 
public void TotalCostOfDinnerReturnsCorrectTotalForNonSenior() 
{ 
    DinnerViewModel dvm = new DinnerViewModel 
    { 
     Meal = new Meal { Cost = 7M }, 
     Beverage = new Beverage { Cost = 1M }, 
     Desert = new Desert { Cost = 2M }, 
     SalesTax = 0.08M, 
     SeniorDiscount = false 
    }; 


    decimal expected = 10.80M; 
    decimal actual = dvm.TotalCostOfDinner; 

    Assert.AreEqual(expected, actual, "The actual value does not match the expected value."); 
} 
+0

我使用实际的ViewModel创建库存数据输入表单(将新项目添加到一个数据库)。要在一页中完成这一切,我必须使用虚拟机将许多不同的模型合并在一起。表单提交后,我必须将虚拟机中的数据映射到相应的模型,以便将所有内容保存到数据库中。我没有在Controller中做这个映射,而是将逻辑移入Helper。 Controller将VM发送给Helper,Helper完成它的工作,将新的Item保存到数据库,如果一切顺利,返回'true'。 – Jason

相关问题