MVC: Unit Testing in MVC

Today is the second day since I changed my blog websites in WordPress, so it’s time to add something new into my poor repository.

I have described my opinions on ASP.NET MVC5 by the old posts, and then I began learning this open-source framework for some weeks, today I will write something that I have learnt about the Unit-Test feature in ASP.NET MVC5. Now, let’s begin.

As we all know that unit-test is very important to an application in the patterns or opinions of extensibility, flexibility and modern.

There is a description to Unit-Testing in Wikipedia:

In computer programming, unit testing is a software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use. Intuitively, one can view a unit as the smallest testable part of an application. In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure. In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method. Unit tests are short code fragments created by programmers or occasionally by white box testers during the development process. It forms the basis for component testing.
Ideally, each test case is independent from the others. Substitutes such as method stubs, mock objects,[5] fakes, and test harnesses can be used to assist testing a module in isolation. Unit tests are typically written and run by software developers to ensure that code meets its design and behaves as intended.

So the problem here is what should we do if we want to add the feature of unit-testing into our MVC project. Come with me, and the steps are over here:

  1. A demo of ASP.NET MVC prepared;
  2. Visual Studio 2015 or any other versions supported;
  3. Network is necessary, that’s all.

Now if all of them prepared, we are ready to begin.

1st: Create your code logic

The first step to do is creating a new controller with empty-module because I assume that the demo you have created is empty.

Like this:

namespace EssentialTools.Controllers {
    public class HomeController : Controller {
        public ActionResult Index() {
            return View();
        }
    }
}

Oh, it’s so empty that it makes you feel terrible, right? Well, it’s none of my business, aha. And in fact, we really needn’t too much code here because it’s only a demo. Then we should create a model class which we will create logic with. The name of this class is not important, just like what I have done:

namespace EssentialTools.Models {
    public class Product {
        public int ProductID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        public string Category { get; set; }
    }

    public class MinimumDiscountHelper : IDiscountHelper {
            public decimal ApplyDiscount(decimal totalParam) {
                if (totalParam < 0)
                    throw new ArgumentOutOfRangeException();
                if (totalParam < 10)
                    return totalParam;
                if (totalParam <= 100)
                    return totalParam - 5;
                else
                    return totalParam * 0.9M;
            }
        

}
The interface here you can ignore because  here doesn’t involve the concept of Inversion of control, Dependency injection or the loosely-coupled components.
I have add a new Helper in this class because it’s the guy that well will test in the Unit-Testing after. It means that , if you cost more than 100 dollars, you will enjoy 90 percent discount, and if you cost between 10 and 100 dollars, the consumption will minus 5 dollars, and if you cost less than 10 dollars, you won’t enjoy discount any more. But it’s obviously that your consumption can’t less than zero, it’s impossible, so the negative numbers input is invalid and system will throws an ArgumentOutOfRangeException.

 

Ok, the preparation is well done, and we will enter the next.

2nd: Add Unit-Testing project in this solution

Add a new project which pattern is “unit-test”, and add the necessary reference to it. I will use the default framework of unit-testing in ASP.NET MVC , but any other third-party framework is also allowed because the MVC is extensible.

The new test project will have a default class like this:

namespace EssentialTools.Tests {
    [TestClass]
    public class UnitTest1 {

        [TestMethod]
        public void TestMethod01() {

        }
     }
}

It’s empty as well, so we add some code into it:

namespace EssentialTools.Tests {
    [TestClass]
    public class UnitTest1 {

        private MinimumDiscountHelper getTestObject() {
            return new MinimumDiscountHelper();
        }

        [TestMethod]
        public void Discount_Above_100() {

            MinimumDiscountHelper target = getTestObject();
            decimal total = 200;

            var discountTotal = target.ApplyDiscount(total);

            Assert.AreEqual(total * 0.9M, discountTotal);

        }

        [TestMethod]
        public void Discount_Between_10_And_100() {

            MinimumDiscountHelpertarget = getTestObject();

            var TenDollarDiscount = target.ApplyDiscount(10);
            var HundredDollarDiscount = target.ApplyDiscount(100);
            var FiftyDollarDiscount = target.ApplyDiscount(50);

            Assert.AreEqual(5, TenDollarDiscount);
            Assert.AreEqual(95, HundredDollarDiscount);
            Assert.AreEqual(45, FiftyDollarDiscount);
        }

        [TestMethod]
        public void Discount_Blow_10() {

            MinimumDiscountHelper target = getTestObject();

            var FiveDollarDiscount = target.ApplyDiscount(5);
            var ZeroDollarDiscount = target.ApplyDiscount(0);

            Assert.AreEqual(5, FiveDollarDiscount);
            Assert.AreEqual(0, ZeroDollarDiscount);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void Discount_Nagetive_Total() {

            MinimumDiscountHelper target = getTestObject();

            target.ApplyDiscount(-1);
        }
    }
}

Join the so long code here in sudden must makes confused, so I will give a explanation for this.

“[TestClass]” and “[TestMethod]” are attributes defined by the test-framework, and are the magic source of this unit-testing project. If you miss them, your classes or methods will be the same as the common classes and methods, and the unit-testing will not works. Of course, you can add common methods and classes in the test class, it’s allowed because you may need something to help building your test-project and this common code is necessary.

In unit-testing, there should be three steps to be done before running the tests. It’s Arrange-Act-Assert(AAA).

Arrange:

Your should make everything ready here, such as create instance and initialize data.

For example:

// Arrange
MinimumDiscountHelper target = getTestObject();
decimal total = 200;

We create a new instance of MinimumDiscountHelper , and initialize the price as 200 dollars.

Act:

After arranged, do the test at this place:

// Act
var discountTotal = target.ApplyDiscount(total);

Check the discount and get the result here.

Here is the main party of the test method, which contains the logic of this founction or feature, so write the code correctly or you will get a wrong result.

Assert:

After actions done, you should make a assertions here to check if the result equal to the expectations, if not, test failed.

// Assert
Assert.AreEqual(total * 0.9M, discountTotal);

The “Assert” is a static class which contains many static methods for check the assertions in this test period. Each of these methods has a override one to contain a special error-message for failed-result shown to the tester. Each of these return a Boolean value shown if the test passed or not.

In the last test method, there is a”[ExpectedException(typeof(ArgumentOutOfRangeException))]” defined at the head of the method, it means that the method will only throws “ArgumentOutOfRangeException” as a expected exception, and will fetch it, so you don’t need to use “try-catch” to get the exceptions. It’s obviously make your code clean and tidy.

We should follow these rules so that your code will be more readable and specific. Anyway, it’s only a suggestion.

3rd: Start Unit-Test work

Now, we can start the test work.

Click the panel “TEST” in the VS, and open the Test resource window. If you can’t see your test methods here, you should build your project first.

Select a method to run or run all of the test methods, to check if some error throws.

If some error throws, review your code and resolve the problems, until your screen change to the view like this:

screenshot-168

Well, my dashboard is not the same as it should be because I also have some different unit-testing work to do with. But in a word, all tests should be passed.

Anyway, if you build your unit-testing feature like this, it’s still weak and inflexible because it may go wrong if you change the Helper’s name, or even some small changes in the source code. Design by the loosely-coupled components and using interface is a good way to resolve this trouble, but it not the point here.

That’s all, so many syntax error because my horrible English….

I think I should have a rest, still in fever .

5,570 thoughts on “MVC: Unit Testing in MVC”

  1. 增达网:逆向网赚,五五倍增,自动下滑,十级提成。

    终生只需99元,加入增达网VIP会员,享受以下特权:

    ①,让成千上万人每天浏览你的广告,强制浏览时间。

    ②,免费下载群发软件,无使用限制,全部是破解版。

    ③,让你什么不干躺着就赚钱,上线替下线发展会员。

    注册网址:

    http://www.lin152.zengd.com/

    增达网

  2. 沃八达,逆向导购,自动下滑,三三倍增,十级提成。

    ①注册提成。有人在你网站注册你就有钱,阶梯制,最低每个 1 毛,最高 1 元。

    ②下线提成。逆向推荐模式,上线替下线发展,就算不推广,照样有钱赚,见点 5 元。

    ③直推提成。你自己每推荐一个VIP下线提成 50 元,满 3个开始下滑,但提成不会减少。

    营销软件,无限下载,每日增加,永久更新。

    免费注册网址:

    http://www.lin152.wobada.com/?Action=xm2

    沃八达

Leave a Reply

Your email address will not be published. Required fields are marked *