【问题标题】:C# ASP.NET MVC Controller unit testC# ASP.NET MVC 控制器单元测试
【发布时间】:2016-08-14 17:22:25
【问题描述】:

我对单元测试有点陌生,我想知道我做的是否正确。

//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);
}

我做得对吗,有没有更好的方法或者这样好吗?

任何反馈都将不胜感激,在此先感谢。

【问题讨论】:

    标签: c# asp.net-mvc unit-testing testing


    【解决方案1】:

    我真的推荐你使用FluentmvcTesting

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

    你会发现exemples

    【讨论】:

      【解决方案2】:

      这是您可以做到的一种方法。您还可以根据您的模型类型进行验证

      [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 
        } 
      }
      

      【讨论】:

        【解决方案3】:

        我不知道我是否跑题了,但是:你确定你需要测试你的控制器吗? 一般来说,我会遵循“胖模型,瘦控制器”的指导方针(将模型本身视为一个经过适当设计的项目)并将控制器限制为解析请求。 这应该会给你留下微不足道的代码,我不会费心去测试它。

        换句话说,我不会费心测试任何返回 ActionResult 的方法。

        如果您的控制器中有算法代码并且想要对其进行测试,我会尝试在操作方法之外对其进行重构,以便单独测试算法部分。

        单元测试很好,但是很昂贵,而且它不是灵丹妙药:如果你的代码足够琐碎,我建议你可以不进行单元测试。

        想一想:你在测试什么?如果它是可以重构或分解的东西,那么无论如何都要对它进行单元测试。但是,如果真的没有什么东西可以分解,那就不要在控制器上浪费时间,并为您的模型设置适当的测试。

        【讨论】:

          【解决方案4】:

          这是我已经使用了一段时间的单元测试结构。它基于我从 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);
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-12-01
            • 1970-01-01
            • 2011-01-30
            • 2010-09-26
            相关资源
            最近更新 更多