2013-10-24 96 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

相關問題