3

I'm kind of new to unit testing and I am wondering if I'm doing it correct or not.

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

Am I doing it right, is there a better way or is this good?

Any feedback would be appreciated, thanks in advance.

rashfmnb
  • 9,959
  • 4
  • 33
  • 44
foxtrot2nov
  • 144
  • 2
  • 9

4 Answers4

2

Here is a way you can do it. You can also verify based on your model type

[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 
  } 
}
Akanksha Gaur
  • 2,636
  • 3
  • 26
  • 50
2

Here's a structure for unit tests I've been using for a little bit. It's based off an a SpecificationBase class I found from I think Jimmy Bogard on LosTechies.

The nice thing here is each scenario is encapsulated into it's own class. And then you read the tests it sounds natural.

This assumes NUnit and FakeItEasy are being used, but it could modified for 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 { }

Then here's the actual contoller tests

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

        }
    }
}

and here is the controller it is testing

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);
    }
}
Fran
  • 6,440
  • 1
  • 23
  • 35
1

I really recommend you to use FluentmvcTesting

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

You will find exemples

Arnaud
  • 84
  • 1
  • 10
0

I don't know if I'm going out of topic but: are you sure you need to test your Controllers? Generally, I would follow the guideline "Fat Model, Skinny Controller" (considering Model as a properly engineered project per se) and restrict the Controller to the parsing of the Request. This should leave you with trivial code, and I wouldn't bother testing it.

In other words, I wouldn't bother testing any method that returns an ActionResult.

If you have algorithmic code in your controller and you want to test it, I would try to refactor it outside of the action methods, in order to test the algorithmic part in isolation.

Unit testing is good, but expensive, and it's not a magic bullet: if your code is trivial enough, I advocate you can go by without unit testing it.

Think about this: what are you testing? If it's something that could be refactored or break up, then unit test it, by any means. But if there is really nothing that can break up, don't waste your time on controllers and set up proper tests for your model.

Alberto Chiesa
  • 7,022
  • 2
  • 26
  • 53