Tag Archives: Tdd

Create angularjs service to let the test pass – to be continue…

Create angularjs service is very easy, in anguarjs 1.x have 4 way to create services, but the most of popular way is .factory, and I am going to use the factory function to create an angularjs service and let the angular-mock.js to inject this instance to my test and let my test pass.

In the real life project a lot of people put everything in one of angularjs module, but today we are going to follow  the TDD principle, I will follow the best practice way for write easy read and testable code. So I will create an separated angularjs module.

Here is the code part start:

Step1: create a folder named: services  under the src folder, and create moviesApi.js file, here is the code for that js file


(function(){
   "use strict";
   
  var app =  angular.module('moviesApi',[]);

    app.factory('moviesApi',function(){
        var service = {};
        service.search = function(query){
                                return {"Search":[{"Title":"Star Wars: Episode IV - A New Hope","Year":"1977","imdbID":"tt0076759","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BZGEzZTExMDEtNjg4OC00NjQxLTk5NTUtNjRkNjA3MmYwZjg1XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: Episode V - The Empire Strikes Back","Year":"1980","imdbID":"tt0080684","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BYmViY2M2MTYtY2MzOS00YjQ1LWIzYmEtOTBiNjhlMGM0NjZjXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode VI - Return of the Jedi","Year":"1983","imdbID":"tt0086190","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BODllZjg2YjUtNWEzNy00ZGY2LTgyZmQtYTkxNDYyOWM3OTUyXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: The Force Awakens","Year":"2015","imdbID":"tt2488496","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BOTAzODEzNDAzMl5BMl5BanBnXkFtZTgwMDU1MTgzNzE@._V1_SX300.jpg"},{"Title":"Star Wars: Episode I - The Phantom Menace","Year":"1999","imdbID":"tt0120915","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BM2FmZGIwMzAtZTBkMS00M2JiLTk2MDctM2FlNTQ2OWYwZDZkXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode III - Revenge of the Sith","Year":"2005","imdbID":"tt0121766","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNTc4MTc3NTQ5OF5BMl5BanBnXkFtZTcwOTg0NjI4NA@@._V1_SX300.jpg"},{"Title":"Star Wars: Episode II - Attack of the Clones","Year":"2002","imdbID":"tt0121765","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNDRkYzA4OGYtOTBjYy00YzFiLThhYmYtMWUzMDBmMmZkM2M3XkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008","imdbID":"tt1185834","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTI1MDIwMTczOV5BMl5BanBnXkFtZTcwNTI4MDE3MQ@@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008–2015","imdbID":"tt0458290","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTM0NjQ2Mjk0OV5BMl5BanBnXkFtZTcwODQ3Njc3Mg@@._V1_SX300.jpg"},{"Title":"Star Wars: Clone Wars","Year":"2003–2005","imdbID":"tt0361243","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMjE2Mjk5Mzk3M15BMl5BanBnXkFtZTcwMDkzMTIzMQ@@._V1_SX300.jpg"}],"totalResults":"354","Response":"True"};
                        };   

                   
                        
                    
   return service;

 });

})()

Now go back to your test spec file, using angular-mock to mock your module and inject the service:


angular.mock.module('moviesApi');//mock the module 
angular.mock.inject(function(_moviesApi_){//inject your real servies
            service = _moviesApi_;
        });


The movies.services.js should look like this:


describe('data services',function(){
    var moviesData = {"Search":[{"Title":"Star Wars: Episode IV - A New Hope","Year":"1977","imdbID":"tt0076759","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BZGEzZTExMDEtNjg4OC00NjQxLTk5NTUtNjRkNjA3MmYwZjg1XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: Episode V - The Empire Strikes Back","Year":"1980","imdbID":"tt0080684","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BYmViY2M2MTYtY2MzOS00YjQ1LWIzYmEtOTBiNjhlMGM0NjZjXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode VI - Return of the Jedi","Year":"1983","imdbID":"tt0086190","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BODllZjg2YjUtNWEzNy00ZGY2LTgyZmQtYTkxNDYyOWM3OTUyXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: The Force Awakens","Year":"2015","imdbID":"tt2488496","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BOTAzODEzNDAzMl5BMl5BanBnXkFtZTgwMDU1MTgzNzE@._V1_SX300.jpg"},{"Title":"Star Wars: Episode I - The Phantom Menace","Year":"1999","imdbID":"tt0120915","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BM2FmZGIwMzAtZTBkMS00M2JiLTk2MDctM2FlNTQ2OWYwZDZkXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode III - Revenge of the Sith","Year":"2005","imdbID":"tt0121766","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNTc4MTc3NTQ5OF5BMl5BanBnXkFtZTcwOTg0NjI4NA@@._V1_SX300.jpg"},{"Title":"Star Wars: Episode II - Attack of the Clones","Year":"2002","imdbID":"tt0121765","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNDRkYzA4OGYtOTBjYy00YzFiLThhYmYtMWUzMDBmMmZkM2M3XkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008","imdbID":"tt1185834","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTI1MDIwMTczOV5BMl5BanBnXkFtZTcwNTI4MDE3MQ@@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008–2015","imdbID":"tt0458290","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTM0NjQ2Mjk0OV5BMl5BanBnXkFtZTcwODQ3Njc3Mg@@._V1_SX300.jpg"},{"Title":"Star Wars: Clone Wars","Year":"2003–2005","imdbID":"tt0361243","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMjE2Mjk5Mzk3M15BMl5BanBnXkFtZTcwMDkzMTIzMQ@@._V1_SX300.jpg"}],"totalResults":"354","Response":"True"};

    it('should return search movies data',function(){
        var service = {};

        angular.mock.module('moviesApi');


        angular.mock.inject(function(_moviesApi_){
            service = _moviesApi_;
        })

        expect(service.search('star wars')).toEqual(moviesData);
    })
});

Now your test will be pass.

But still the moviesApi.js I hardcode the data over there, it is not what I want, next post, I will write code how to do HTTP test.

To be continue…

Advertisements

TDD AngularJs Services Test- continue with last post

Currently a lot of developer team like follow by the TDD pattern, it means that write your test first then write the code to let it pass.

Any app either is for display data or just for possessing data, so my first test that I lik to build the data services first. And know we need follow the TDD principle, so we need to create the test first.

Continue with my last post, then I create a folder name services under the spec folder and create a movies.services.spec.js.

Now  here is my first test:


describe('data services',function(){
    var moviesData = {"Search":[{"Title":"Star Wars: Episode IV - A New Hope","Year":"1977","imdbID":"tt0076759","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BZGEzZTExMDEtNjg4OC00NjQxLTk5NTUtNjRkNjA3MmYwZjg1XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: Episode V - The Empire Strikes Back","Year":"1980","imdbID":"tt0080684","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BYmViY2M2MTYtY2MzOS00YjQ1LWIzYmEtOTBiNjhlMGM0NjZjXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode VI - Return of the Jedi","Year":"1983","imdbID":"tt0086190","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BODllZjg2YjUtNWEzNy00ZGY2LTgyZmQtYTkxNDYyOWM3OTUyXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: The Force Awakens","Year":"2015","imdbID":"tt2488496","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BOTAzODEzNDAzMl5BMl5BanBnXkFtZTgwMDU1MTgzNzE@._V1_SX300.jpg"},{"Title":"Star Wars: Episode I - The Phantom Menace","Year":"1999","imdbID":"tt0120915","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BM2FmZGIwMzAtZTBkMS00M2JiLTk2MDctM2FlNTQ2OWYwZDZkXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode III - Revenge of the Sith","Year":"2005","imdbID":"tt0121766","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNTc4MTc3NTQ5OF5BMl5BanBnXkFtZTcwOTg0NjI4NA@@._V1_SX300.jpg"},{"Title":"Star Wars: Episode II - Attack of the Clones","Year":"2002","imdbID":"tt0121765","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNDRkYzA4OGYtOTBjYy00YzFiLThhYmYtMWUzMDBmMmZkM2M3XkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008","imdbID":"tt1185834","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTI1MDIwMTczOV5BMl5BanBnXkFtZTcwNTI4MDE3MQ@@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008–2015","imdbID":"tt0458290","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTM0NjQ2Mjk0OV5BMl5BanBnXkFtZTcwODQ3Njc3Mg@@._V1_SX300.jpg"},{"Title":"Star Wars: Clone Wars","Year":"2003–2005","imdbID":"tt0361243","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMjE2Mjk5Mzk3M15BMl5BanBnXkFtZTcwMDkzMTIzMQ@@._V1_SX300.jpg"}],"totalResults":"354","Response":"True"};

    it('should return search movies data',function(){
        var service = {};

        expect(service.search('star wars')).toEqual(moviesData);
    })
});

By the way, before I start I already run npm test, so you could see my test is fail.

firstfailexpect

So next we are going to write a code to let it pass.


describe('data services',function(){
    var moviesData = {"Search":[{"Title":"Star Wars: Episode IV - A New Hope","Year":"1977","imdbID":"tt0076759","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BZGEzZTExMDEtNjg4OC00NjQxLTk5NTUtNjRkNjA3MmYwZjg1XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: Episode V - The Empire Strikes Back","Year":"1980","imdbID":"tt0080684","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BYmViY2M2MTYtY2MzOS00YjQ1LWIzYmEtOTBiNjhlMGM0NjZjXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode VI - Return of the Jedi","Year":"1983","imdbID":"tt0086190","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BODllZjg2YjUtNWEzNy00ZGY2LTgyZmQtYTkxNDYyOWM3OTUyXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: The Force Awakens","Year":"2015","imdbID":"tt2488496","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BOTAzODEzNDAzMl5BMl5BanBnXkFtZTgwMDU1MTgzNzE@._V1_SX300.jpg"},{"Title":"Star Wars: Episode I - The Phantom Menace","Year":"1999","imdbID":"tt0120915","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BM2FmZGIwMzAtZTBkMS00M2JiLTk2MDctM2FlNTQ2OWYwZDZkXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode III - Revenge of the Sith","Year":"2005","imdbID":"tt0121766","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNTc4MTc3NTQ5OF5BMl5BanBnXkFtZTcwOTg0NjI4NA@@._V1_SX300.jpg"},{"Title":"Star Wars: Episode II - Attack of the Clones","Year":"2002","imdbID":"tt0121765","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNDRkYzA4OGYtOTBjYy00YzFiLThhYmYtMWUzMDBmMmZkM2M3XkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008","imdbID":"tt1185834","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTI1MDIwMTczOV5BMl5BanBnXkFtZTcwNTI4MDE3MQ@@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008–2015","imdbID":"tt0458290","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTM0NjQ2Mjk0OV5BMl5BanBnXkFtZTcwODQ3Njc3Mg@@._V1_SX300.jpg"},{"Title":"Star Wars: Clone Wars","Year":"2003–2005","imdbID":"tt0361243","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMjE2Mjk5Mzk3M15BMl5BanBnXkFtZTcwMDkzMTIzMQ@@._V1_SX300.jpg"}],"totalResults":"354","Response":"True"};

    it('should return search movies data',function(){
        var service = {};
        service.search = function (){
            return moviesData;
        }

        expect(service.search('star wars')).toEqual(moviesData);
    })
});
firstfailexpectpass

Now the test is passed, but this is not what we want, we want is an angularjs service instance.

That is my next post.  - to be continue...

 

Introduction Set up TTD for Angular App – to be continue

Step 1 : go to Jasmine release page https://github.com/jasmine/jasmine/releases download the standalone zip file.

Step2: create a project folder in your computer where you like to put it, unzip the jasmine standalone zip file inside your project folder, then we could delete the sample files inside src and spec folder since we won’t using it, but keep the folder, so we could still using it.

Step3:  run npm init (make sure nodejs has been install in your computer) will create package.json file

Step4: install karma as test runner

npm install karma --save-dev

Step5: install -g karma-cli

Step6: npm install karma-jasmine karma-chrome-launcher –save-dev

Step7:karma init (for add the config file for karma)

test

Step 8: normal running test in phantom is fast so also need install packages:

“karma-phantomjs-launcher”: “^0.2.1”,
“phantomjs”: “^1.9.18”

Now your package.json file will look like this


{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
     "test": "karma start karma.conf.js"
  },
  "keywords": [
    "sample"
  ],
  "author": "sandy zhang",
  "license": "ISC",
  "devDependencies": {
    "jasmine-core": "^2.3.4",
    "karma": "^0.13.9",
    "karma-chrome-launcher": "^0.2.0",
    "karma-jasmine": "^0.3.6",
    "karma-phantomjs-launcher": "^0.2.1",
    "phantomjs": "^1.9.18"
  }
}

Step9: Add angularjs and angular-mock.js into the lib folder, and included it into the karma config file


// Karma configuration
// Generated on Sat Nov 12 2016 22:15:24 GMT+1100 (AUS Eastern Daylight Time)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',


    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],


    // list of files / patterns to load in the browser
    files: [
      'lib/angular/angular.min.js',
      'lib/angular/angular-mocks.js',
      'src/**/*.js',
      'spec/**/*.js'
    ],


    // list of files to exclude
    exclude: [
    ],


    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },


    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],


    // web server port
    port: 9876,


    // enable / disable colors in the output (reporters and logs)
    colors: true,


    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],


    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}

Now I create a calculater.js file inside src folder with one function

function add(x,y){
return x+y;
};

And create your first calculater.spec.js inside spec folder

describe(‘calculator’,function(){
it(‘should add two number’,function(){
expect(add(1,2)).toBe(3);
})
});

then run npm test, then your will get your result.

firsttest.JPG

 

Example test your controller, Nunit test

for you home controller:

using System.Web.Mvc;

namespace WestBanking.Controllers
{
    public class HomeController : Controller
    {
       

        public ActionResult Index()
        {
            return Redirect("http://netbank.test.com");
        }
    }
}

here is your test

using WestBanking.Controllers;
using NUnit.Framework;
using TestStack.FluentMVCTesting;

namespace WestBanking.ControllerTests   
{
    [TestFixture]
    public class HomeControllerTests
    {
        [Test]
        public void ShouldRedirect()
        {
            var sut = new HomeController();

            sut.WithCallTo(x => x.Index()).ShouldRedirectTo("http://netbank.test.com");
        }
    }
}

Example of using moq in your nunit test

When you do unit test, we won’t use the real server to do the test, the moq package could help us do the dependence inject.

here is the sample example how to use moq to mock your inject classes

using WestBanking.Models;
using Moq;
using NUnit.Framework;

namespace BankingSite.UnitTests
{
    [TestFixture]
    public class LoanApplicationScorerTests
    {
        [Test]
        public void ShouldDecline_TooYoung()
        {
            var fakeCreditChecker = new Mock();            
            
            //go pass the CheckCredit method
            fakeCreditChecker.Setup(
                x => x.CheckCredit(It.IsAny<int>())
                .Returns(true);
            //inject the fake instance here
            var sut = new LoanApplicationScorer(fakeCreditChecker.Object);

            var application = new LoanApplication
                              {
                                  Age = 21
                              };

            sut.ScoreApplication(application);

            Assert.That(application.IsAccepted, Is.False);
        }


        [Test]
        public void ShouldOK_Young_Wealthy()
        {
            var fakeCreditChecker = new Mock();

            fakeCreditChecker.Setup(
                x => x.CheckCreditHistory(It.IsAny<int>())
                .Returns(true);

            var sut = new LoanApplicationScorer(fakeCreditChecker.Object);

            var application = new LoanApplication
            {
                AnnualIncome = 1500000.01m,
                Age = 21
            };

            sut.ScoreApplication(application);

            Assert.That(application.IsAccepted, Is.True);
        }


        [Test]
        public void ShouldDecline_NotYoung_PoorCredit()
        {
             //create a instance of fake class
            var fakeCreditHistoryChecker = new Mock();

            fakeCreditChecker.Setup(
                x => x.CheckCreditHistory(It.IsAny<int>()))
                .Returns(false);

            var sut = new LoanApplicationScorer(fakeCreditHistoryChecker.Object);

            var application = new LoanApplication
            {
                AnnualIncome = 30000.01m,
                Age = 30
            };

            sut.ScoreApplication(application);

            Assert.That(application.IsAccepted, Is.False);
        }


    }
}

Write your first Unit test – Test your model

For example you have very simple code like this:

namespace WestBanking.Models
{
    public class CheckCredit: ICreditChecker
    {
        public bool IsCreditWorthy(int credit)
        {
            // Simulate actual credit check

            if (credit<200)
            {
                return false;
            }

            return true;
        }
    }
}

For the test code:

using WestBank.Models;
using NUnit.Framework;

namespace BankingSite.UnitTests
{
    [TestFixture]
    public class CreditCheckerTests
    {
        [Test]
        public void BadCredit()
        {
            //sut: system under test
            var sut = new CreditChecker();

            var isCreditWorthy = sut.IsCreditWorthy(100);

            Assert.That(isCreditWorthy, Is.False);
        }

        [Test]
        public void GoodCredit()
        {
            var sut = new CreditChecker();

            var isCreditWorthy = sut.IsCreditWorthy(1000);

            Assert.That(isCreditWorthy, Is.True);
        }
    }
}

Nunit test in Visio Studio – Set up – To be continue

Recently my job need write all the unit test for my project and I haven’t done this before, and I like share my experience here, and hope that could help someone else.

First, Install an test runner  that will help you do the test in Visual Studio.

Tool > extension and updates > search online> nunit test adapter

nunit test

Second, create an test project

Third, Open the PM console, install some useful packages:

Nunit

Moq

TestStack.FluentMVCTesting