ASP. net mvc unit testing in minutes

Source: Internet
Author: User
Tags xunit

ASP. net mvc unit testing in minutes
1. Why should we perform unit tests? Most developers have a habit (including themselves) and often do not like to perform unit tests. Because we are always blind and confident about the programs we write, or we are lucky to leave them to the testing team's sisters after each passing operation. As a result, a lot of bugs appeared in my sister's test. Every time I saw my sister come over, I just wanted to say a word: Are you a monkey for teasing? Originally, I wanted to save time. In the end, I spent more time searching for bugs and fixing bugs than I did developing this module. what's even worse at the end is that, it is inevitable that you work overtime! If we put bugs in the bud at the beginning, are we so hard? SO, unit testing is necessary! Ii. unit test rules 1. unit test must be executed repeatedly, that is, it can be executed very frequently. 2. The execution speed of unit test cannot be too slow, otherwise, it will affect the development progress. 3. unit testing should not rely on external resources and real environments. 4. unit testing should not involve operations on real databases. 5. ensure the reliability of unit testing. 6. unit Testing is usually based on testing a method. 7. Every programmer needs to write unit test code for his own code. 3. unit test tool I only recommend a more practical one here. test Tool NUnit, it can be used independently or through TestDriven. NET (TestDriven. NET is a unit test tool integrated in Visual Studio IDE in the form of plug-ins, fully compatible with all. NET Framework version, and integrated with a variety of unit test frameworks such as NUnit, MbUnit, and MS Team System) to add it to. As A. Net member in the xUnit family, NUnit is A. NET unit testing framework. xUnit is a unit testing tool suitable for multiple languages. It has the following features: it provides APIs so that we can create repeated units with "pass/fail" results. Includes the tools required to run the test and present the results. Multiple tests can be run as a group in one batch. It is very clever and easy to operate. It takes a little time to learn and does not add additional burden to the testing program. Functions can be expanded. If you want more functions, you can easily expand them. The old saying goes: it is today. one of the most powerful testing tools in the NET field is. there are actually a lot of Unit Test tools under. I don't want to talk about them here. We will use the Unit Test Framework provided by Microsoft, which has already been integrated into ~ 4. The objective of MOQ unit testing is to test only one method at a time, which is a fine-grained test. However, if a method depends on other difficult external tasks, for example, what should we do with network connection and database connection? Since the unit test rule says that it is not easy to depend on these external real things, can I just copy one? In this case, the unit test is completed in a hypothetical manner. In fact, we use a Mock object, a substitute for a real object, and use the Moq framework to simulate a Mock object. It provides us with the ability to simulate real object behavior, it is then handed over to the tested function to determine whether the tested function is correct. Note: Moq can only simulate interfaces or abstract classes. You can use Nuget to obtain Moq and reference it to the specified project, or download it on google. Remember to reference Moq. dll in the test project anyway ~ For example, copy the public class Student {public string ID {get; set;} public string Name {get; set;} public int Age {get; set ;}} copy the code IStudentRepository public interface IStudentRepository {Student GetStudentById (string id);} below is the unit test code of the GetStudentById method: copy the Code [TestMethod] public void GetStudentByIdTest () {// create a MOCK object var mock = new Mock <IStudentRepository> (); // set MOCK call behavior mock. setup (p => p. getStudentById ("1 ")). returns (new Student (); // MOCK call method mock. object. getStudentById ("1"); Assert. areNotSame (new Student (), mock. object. getStudentById ("1");} copying the code here is actually a hypothetical truth, because the method in the real interface IStudentRepository GetStudentById must actually access the database, in this case, we can directly use the IStudentRepository interface to simulate an object without implementation. This instantly improves the feasibility of unit testing. However, we should also mention that when writing code, do not make the code overly dependent so that it can proceed smoothly during unit testing! About common Moq members: 1. Mock <T>: Through this class, we can get a Mock <T> object. T can be interfaces and classes. It has a public Object attribute, which is the Object we simulate by Moq. Var mo = new Mock <IStudentRepository> (); mo. Object // is an Object simulating the IStudentRepository interface. 2. It: This is a static class used to filter parameters. It Is suitable for matching numbers and string parameters. It provides the following static methods: Is <TValue>: the parameter Is Expression <Predict <TValue> type, you can use it if you need a certain type and the type needs to be determined by code. IsAny <TValue>: No parameter. A TValue can be matched successfully. IsInRange <TValue>: Used to match parameters between two TValue types. (The Range parameter can be set to an open and closed interval) IsRegex: matches with a regular expression. (Only for string type parameters) copy the code var customer = new Mock <ICustomer> (); customer. setup (x => x. selfMatch (It. is <int> (I => I % 2 = 0 ))). returns ("1"); // method SelfMatch accepts the int type parameter. If the parameter is an even number, string 1 is returned. Customer. setup (p => p. selfMatch (It. isAny <int> ())). returns (int k) => "any number:" + k); // The method SelfMatch accepts the int type, and any int type parameter is allowed, and then Returns: "Any Number: "+ k. Customer. setup (p => p. selfMatch (It. isInRange <int> (0, 10, Range. (Inclusive ))). returns ("number less than 10"); // The method SelfMatch accepts the int type, and Returns the number of customers less than 10 only when the range is [0, 10. setup (p => p. showException (It. isRegex (@ "^ \ d + $ "))). throws (new Exception ("cannot be a number"); // use a regular expression to filter parameters. The parameter cannot be a number copy code. 3. MockBehavior: used to configure MockObject behaviors, such as whether to automatically mock. Moq has an enumeration type MockBehavior, which has three values: Strict, Loose, and Default. Strict indicates that the Mock object must be Mock before calling a method. Otherwise, a MockException is thrown. Loose, on the contrary, does not produce errors if a method without Mock is called. Default is Loose by Default. For example, copy the Code [TestMethod] public void MoqTest () {var mo = new Mock <ICustomer> (MockBehavior. strict); mo. object. method (); // In MockBehavior. in Strict settings, an exception is thrown when you call unfilled methods, properties, or events.} copy Code 4. MockFactory: Mock object factory, which can generate Mock objects with unified custom configurations in batches, you can also perform Mock object testing in batches. This is a factory for simulating objects. We cannot Mock them in batches. For example, copy the code var factory = new MockFactory (MockBehavior. strict) {DefaultValue = DefaultValue. mock}; // Create a mock using the factory settings var aMock = factory. create <IStudent> (); // Create a mock overriding the factory settings var bMock = factory. create <ITeacher> (MockBehavior. loose); // Verify all verifiable expectations on all mocks created through the factory. Verify (); copy Code 5 and Match <T>: If you first think It is not enough, use Match <T> to completely customize rules. For example, we recommend that you copy the [TestMethod ()] public void MoqTest () {var mo = new Mock <IRepository> (); mo. setup (p => p. method (MatchHelper. paramMatcher ("wang "))). returns ("success"); Assert. areEqual (mo. object. ("wang"), "success);} // The Custom Parameter Match public static class MatchHelper {public static string ParamMatcher (string name) is implemented here) {return Match <string>. create (p => p. equals (name) ;}} copy Code 6, Verify, and VerifyAll to test mo Whether the method or attribute of the ck object is called for execution. Verify must call the Verifiable () method before it can be used, and VerifyAll can Verify all the mock objects without using it. For example: copy the public void TestVerify () {var customer = new Mock <ICustomer> (); customer. setup (p => p. getCall (It. isAny <string> ())). returns ("method call "). verifiable (); // you must call the Verifiable () method to access customer. object. getCall ("called! "); Customer. verify ();} public void TestVerifyAll () {var customer = new Mock <ICustomer> (); customer. setup (p => p. getCall (It. isAny <string> ())). returns ("method call"); // The Verifiable () method cannot be explicitly called. object. getCall ("called! "); Customer. VerifyAll ();} copy code 7. Callback is actually a Callback. Using Callback can notify us when a method that matches with specific parameters is called. When executing a method, call the internal input (Action) Delegate, for example, copy the code public void TestCallback () {var customer = new Mock <ICustomer> (); customer. setup (p => p. getCall (It. isAny <string> ())). returns ("method call "). callback (string s) => Console. writeLine ("OK" + s); customer. object. getCall ("x");} copy Code 5, ASP. net mvc unit test application suggestions: 1. Whenever you add a series of new functions to the controller, service, and repository layers, you start to modify the code, you have to take on the risks that may damage the functions that work normally. To put it bluntly, you must perform a unit test. 2. unit tests must be executed quickly. Therefore, for time-consuming database interaction, You Must mock it, and then write code to interact with the mock database. 3. You do not need to perform unit tests for the view. To test the view, you have to build a web server. Because building a web server is relatively time-consuming, it is not recommended to perform unit tests on The view. If your view contains a large number of complex logics, you should consider transferring these logics to the Helper method. You can write unit tests for the Helper method without building a web server. 4. For http-related things, you must also mock how to add unit tests for the methods? 1. Add a default unit test project to the project when creating an MVC project. For example, 2. Right-click the corresponding method in vs and choose add unit test ,: the default unit test code generated by the MVC unit test has already generated the corresponding unit test method for the Controller. For example, for the HomeController unit test, pay attention to the naming rules of the test class and the two features TestClass and TestMethod, with these two things, you can test classes and methods. We can find that the unit test is conducted in the arrange/act/assert mode. To put it bluntly, the unit test follows three steps: arrange: the initial test environment is in the preparation stage; act: executes the test; assert: assert. Copy the Code [TestClass] public class HomeControllerTest {[TestMethod] public void About () {// Arrange HomeController controller = new HomeController (); // Act ViewResult result = controller. about () as ViewResult; // Assert. isNotNull (result) ;}} the difficulty in copying the code is actually in the first step, that is, preparing the test environment. Here we use Moq for simulation. In addition, the Assert class involves the following methods. inconclusive () indicates an unverified test; Assert. areEqual () is used to test whether the specified value is equal. If the values are equal, the test passes. AreSame () is used to verify that the two specified object variables point to the same object. Otherwise, it is considered as an error AreNotSame () it is used to verify that the specified two object variables point to different objects, otherwise it is considered as an error Assert. isTrue () test whether the specified condition is True. If it is True, the test passes; Assert. isFalse () test whether the specified condition is False. If it is False, the test passes; Assert. isNull () tests whether the specified object is a null reference. If it is null, the test passes; Assert. isNotNull () is used to test whether the specified object is non-empty. If not empty, the test passes. A unit test that simulates access to the Service: copy the namespace code. Mvc4UnitTesting. tests. controllers {[TestClass] public class HomeControllerTest {[TestMethod] public void Index () {// Arrange var mockIProductService = new Mock <IProductService> (); mockIProductService. setup (p => p. getAllProduct ()). returns (new List <Product> {new Product {ProductId = 1, ProductName = "APPLE", Price = "5999"}); HomeController controller = new HomeController (mockIProductService. ob Ject); // Act ViewResult result = controller. index () as ViewResult; var product = (List <Product>) result. viewData. model; // Assert. areEqual ("APPLE", product. first <Product> (). productName) ;}}copy the code to a unit test that simulates access to the Web environment. Example: public ActionResult Index () {ViewData ["Message"] = Request. queryString ["WW"]; return View ();} copy the Code [TestMethod] public void Index () {HomeController controller = new HomeControll Er (); var httpContext = new Mock <HttpContextBase> (); var request = new Mock <HttpRequestBase> (); NameValueCollection queryString = new NameValueCollection (); queryString. add ("WW", "WW"); request. setup (r => r. queryString ). returns (queryString); httpContext. setup (ht => ht. request ). returns (request. object); ControllerContext controllerContext = new ControllerContext (); controllerContext. httpContext = http Context. object; controller. controllerContext = controllerContext; ViewResult result = controller. index () as ViewResult; ViewDataDictionary viewData = result. viewData; Assert. areEqual ("WW", viewData ["Message"]);} copy the code to summarize: Effective Testing guarantees the quality of software, so I hope you can, including yourself, all of them can implement unit tests. Currently, the biggest difficulty for us is whether we can model relevant dependent resources right away. Therefore, it is necessary to write low-coupling code. In fact, after you use more exercises, you will naturally be able to cope with relatively complex unit tests. One day you will find that unit tests are only a matter of minutes!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.