2016-04-21 213 views
2

我對單元測試很陌生,我想知道我是否正確地執行它。C#ASP.NET MVC控制器單元測試

//Controller 
public ActionResult Index() 
{ 
    return View("../Message/Index"); 
} 

[TestMethod] 
public void MessageViewCorrectTest() 
{ 
    var controller = new MessageController(); 
    var result = controller.Index() as ViewResult; 
    Assert.AreEqual("../Message/Index", result.ViewName); 
} 

[TestMethod] 
public void MessageViewInCorrectTest() 
{ 
    var controller = new MessageController(); 
    var result = controller.Index() as ViewResult; 
    Assert.AreNotEqual("Something/Else", result.ViewName); 
} 

我做得對嗎,還有更好的方法還是這個好?

任何反饋將不勝感激,提前致謝。

回答

1

這裏有一種方法可以做到這一點。您也可以驗證基於模型類型

[TestMethod] 
public void TestMethod2() 
{ 
    MessageController controller = new MessageController(); 
    ActionResult result = controller.Index(1); 
    Assert.IsInstanceOfType(result, typeof(ViewResult)); 
    //Since view has been asserted as ViewResult 
    ViewResult viewResult = result as ViewResult; 
    if(viewResult != null) 
    {  
    Assert.IsInstanceOfType(viewResult.Model, typeof(YourModelType)); 
    //Further Asserts for your model 
    } 
} 
1

我真的建議你使用FluentmvcTesting

[Test] 
    public void Render_default_view_for_get_to_index() 
    { 
     _controller.WithCallTo(c => c.Index()) 
      .ShouldRenderDefaultView(); 
    } 

你會發現exemples

0

我不知道如果我走出去的話題,但:你確定你需要測試你的控制器?通常,我會遵循「脂肪模型,瘦身控制器」(將模型看作一個正確設計的項目本身)的準則,並將控制器限制爲解析請求。 這應該給你帶來微不足道的代碼,而且我不會去測試它。

換句話說,我不會打擾測試任何返回ActionResult的方法。

如果您的控制器中有算法代碼,並且您想對其進行測試,我會嘗試在操作方法之外對其進行重構,以便單獨測試算法部分。

單元測試是好的,但很昂貴,它不是一個神奇的子彈:如果你的代碼足夠微不足道,我主張你可以不經過單元測試。

想想這個:你在測試什麼?如果它是可以重構或分解的東西,那麼單元測試它,無論如何。但是,如果沒有什麼可以分解的話,不要浪費你的時間在控制器上,併爲你的模型設置適當的測試。

1

這是我一直在使用的單元測試的結構。它基於我認爲在LosTechies上Jimmy Bogard發現的SpecificationBase類。

這裏的好處是每個場景都被封裝到自己的類中。然後你讀了聽起來很自然的測試。

這假定正在使用NUnit和FakeItEasy,但它可以修改爲MS-TEST。

[TestFixture] 
public abstract class SpecificationBase 
{ 
    [SetUp] 
    public void SetUp() 
    { 
     Given(); 
     When(); 
    } 

    protected virtual void Given() { } 
    protected virtual void When() { } 
} 

public class ThenAttribute : TestAttribute { } 

那麼這裏的實際測試位指示

public static class DataControllerTests 
{ 
    public class WhenViewingWesternRegionLoadLookAhead : SpecificationBase 
    { 
     private DataController _sut; 
     private ViewResult _result; 
     private IProvideeDataFeedData _eDataProvider; 

     protected override void Given() 
     { 
      _eDataProvider = A.Fake<IProvideeDataFeedData>(); 
      A.CallTo(() => _eDataProvider.GetAllDayAheadLoad()).Returns(new collectionActualValueData 
      { 
       timestamp = new DateTime(2015, 5, 5), 
       timestampSpecified = true, 
       actualValueData = new[] 
       { 
        new actualValueData {value = 0.1f, name = "Western Region", timestamp = new DateTime(2015, 5, 5)}, 
        new actualValueData {value = 0.1f, name = "some region", timestamp = new DateTime(2015, 5, 5)} 
       } 
      }); 

      _sut = new DataController(_eDataProvider); 
     } 

     protected override void When() 
     { 
      _result = (ViewResult)_sut.Index(); 
     } 

     [Then] 
     public void ViewNameShouldBeCorrect() 
     { 
      Assert.That(_result.ViewName, Is.EqualTo("")); 
     } 

     [Then] 
     public void ModelShouldBeCorrectType() 
     { 
      Assert.That(_result.Model.GetType(), Is.EqualTo(typeof(IndexModel))); 
     } 

     [Then] 
     public void GetAllDayAheadLoadShouldBeCalledOnce() 
     { 
      A.CallTo(() => _eDataProvider.GetAllDayAheadLoad()).MustHaveHappened(Repeated.Exactly.Once); 
     }   
    } 

    public class WhenViewingWesternRegionLoadLookAheadAndValuesAreUnder50000 : SpecificationBase 
    { 
     private DataController _sut; 
     private ViewResult _result; 
     private IndexModel _expectedData; 
     private IProvideeDataFeedData _eDataProvider; 

     protected override void Given() 
     { 
      _expectedData = new IndexModel 
      { 
       Message = "Everything is cool", 
       Region = "Western Region", 
       Values = new Dictionary<DateTime, float> 
       { 
        {new DateTime(2015, 5, 5), 0.1f} 
       } 
      }; 


      _eDataProvider = A.Fake<IProvideeDataFeedData>(); 
      A.CallTo(() => _eDataProvider.GetAllDayAheadLoad()).Returns(new collectionActualValueData 
      { 
       timestamp = new DateTime(2015, 5, 5), 
       timestampSpecified = true, 
       actualValueData = new[] 
       { 
        new actualValueData {value = 0.1f, name = "Western Region", timestamp = new DateTime(2015, 5, 5)}, 
        new actualValueData {value = 0.1f, name = "some region", timestamp = new DateTime(2015, 5, 5)} 
       } 
      }); 

      _sut = new DataController(_eDataProvider); 
     } 

     protected override void When() 
     { 
      _result = (ViewResult)_sut.Index(); 
     } 

     [Then] 
     public void ModelDataShouldBeCorrect() 
     { 
      var model = (IndexModel)_result.Model; 

      Assert.That(model.Message, Is.EqualTo(_expectedData.Message)); 
      Assert.That(model.Region, Is.EqualTo(_expectedData.Region)); 
      Assert.That(model.Values, Is.EquivalentTo(_expectedData.Values)); 
     } 
    } 

    public class WhenViewingWesternRegionLoadLookAheadAndValuesAreOver50000 : SpecificationBase 
    { 
     private DataController _sut; 
     private ViewResult _result; 
     private IndexModel _expectedData; 
     private IProvideeDataFeedData _eDataProvider; 

     protected override void Given() 
     { 
      _expectedData = new IndexModel 
      { 
       Message = "Heavy Load", 
       Region = "Western Region", 
       Values = new Dictionary<DateTime, float> 
       { 
        {new DateTime(2015, 5, 5), 51000f} 
       } 
      }; 

      _eDataProvider = A.Fake<IProvideeDataFeedData>(); 
      A.CallTo(() => _eDataProvider.GetAllDayAheadLoad()).Returns(new collectionActualValueData 
      { 
       timestamp = new DateTime(2015, 5, 5), 
       timestampSpecified = true, 
       actualValueData = new[] 
       { 
        new actualValueData {value = 51000f, name = "Western Region", timestamp = new DateTime(2015, 5, 5)}, 
        new actualValueData {value = 0.1f, name = "some region", timestamp = new DateTime(2015, 5, 5)} 
       } 
      }); 

      _sut = new DataController(_eDataProvider); 
     } 

     protected override void When() 
     { 
      _result = (ViewResult)_sut.Index(); 
     } 

     [Then] 
     public void ModelDataShouldBeCorrect() 
     { 
      //Assert.That(_result.Model, Is.EqualTo(_expectedData)); 
      var model = (IndexModel) _result.Model; 

      Assert.That(model.Message, Is.EqualTo(_expectedData.Message)); 
      Assert.That(model.Region, Is.EqualTo(_expectedData.Region)); 
      Assert.That(model.Values, Is.EquivalentTo(_expectedData.Values)); 

     } 
    } 
} 

,這裏是控制器,它正在測試

public class DataController : Controller 
{ 
    private readonly IProvideeDataFeedData _eDataFeedDataProvider; 

    public DataController(IProvideeDataFeedData eDataFeedDataProvider) 
    { 
     _eDataFeedDataProvider = eDataFeedDataProvider; 
    } 

    public ActionResult Index() 
    { 
     var values = _eDataFeedDataProvider.GetAllDayAheadLoad().actualValueData 
      .Where(a => a.name == "Western Region") 
      .ToDictionary(a => a.timestamp, a => a.value); 

     var model = new IndexModel 
     { 
      Region = "Western Region", 
      Message = values.Any(v => v.Value > 50000) ? "Heavy Load" : "Everything is cool", 
      Values = values 
     }; 

     return View(model); 
    } 
}