2016-04-21 215 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); 
    } 
}