JUnit test controller (MOCKMVC use), Transfer @requestbody data solution

Source: Internet
Author: User
Tags log4j

I. PURPOSE of UNIT Testing

In a nutshell, a test of all logic after we add or change some code, especially after our later revisions (whether it's adding new features or modifying bugs), can do the work of re-testing . To reduce the problem that we have solved even before the release of the issue.

The main point here is to use MOCKMVC to unit test the controller of our system.

The operation of the database is rolled back using the transaction, and the database is still far behind when the method of adding and deleting the database is finished.

Second, the use of MOCKMVC

1, first of all, we have an example,

Import Org.apache.commons.logging.log;import Org.apache.commons.logging.logfactory;import Org.junit.Before;import Org.junit.runner.runwith;import Org.springframework.beans.factory.annotation.autowired;import Org.springframework.http.mediatype;import Org.springframework.test.context.contextconfiguration;import Org.springframework.test.context.junit4.springjunit4classrunner;import Org.springframework.test.context.transaction.transactionconfiguration;import Org.springframework.test.context.web.webappconfiguration;import ORG.SPRINGFRAMEWORK.TEST.WEB.SERVLET.MOCKMVC; Import Org.springframework.test.web.servlet.requestbuilder;import Org.springframework.test.web.servlet.resultactions;import Org.springframework.test.web.servlet.setup.mockmvcbuilders;import Org.springframework.transaction.annotation.transactional;import Org.springframework.web.context.webapplicationcontext;import Static Org.springframework.test.web.servlet.request.mockmvcrequestbuilders.get;import Static Org.springframework.test. web.servlet.request.mockmvcrequestbuilders.post;import Static Org.springframework.test.web.servlet.result.mockmvcresulthandlers.print;import Static org.springframework.test.web.servlet.result.mockmvcresultmatchers.status;/** * Created by Zhengcanrui on 16/8/11. */@RunWith (Springjunit4classrunner.class) @ContextConfiguration (locations={"classpath:spring/ Applicationcontext-*xml "})//The rollback of the configuration transaction, the database additions and deletions will be rolled back to facilitate the reuse of test cases @transactionconfiguration (TransactionManager =" TransactionManager ", Defaultrollback = True) @Transactional @webappconfigurationpublic class Test {//    Remember to configure log4j.properties, the command line output level is debug protected Log logger= Logfactory.getlog (testbase.class);    protected MOCKMVC Mockmvc;    @Autowired protected Webapplicationcontext WAC; @Before ()//This method executes the public void Setup () {MOCKMVC = Mockmvcbuilders.webappcontextsetup (WAC) before each method executes. Build ()  ;  Initialize the Mockmvc object} @org. junit.test public void Getallcategorytest () throws Exception {String responsestring =Mockmvc.perform (Get ("/categories/getallcategory")//requested URL, the requested method is get. Contenttyp E (mediatype.application_form_urlencoded)//Data format. PARAM ("Pcode", "root")//Add parameter). Andexpect (S Tatus (). IsOk ())//The returned status is. Anddo (print ())//print out the request and the corresponding content. Andreturn (). getrespons   E (). getcontentasstring ();    Converts the corresponding data to a string System.out.println ("--------json =" + responsestring); }}

Spring MVC testing often seems more complex. In fact his difference is that he needs a servletcontext to simulate our request and response. But spring also provides a mock test interface of request and response for spring MVC, so that our unit test coverage is more than just the Service,dao layer.

2. Code Explanation:

The @webappconfiguration is a first-level comment that declares a applicationcontext integration test load Webapplicationcontext. The function is to simulate ServletContext

@ContextConfiguration: Because controller,component are used annotations, annotations are required to specify the spring configuration file, scan the appropriate configuration, initialize the class, and so on.

@TransactionConfiguration (TransactionManager = "TransactionManager", Defaultrollback = True) @Transactional

The function of the above two sentences is, let us the operation of the database transaction rollback, such as the addition of the database, after the end of the method, we will revoke the operation of the database.

Why would a transaction be rolled back?

    • The test process of the database operation, will produce dirty data, affecting the correctness of our data
    • Inconvenient cyclic testing, that is, if we delete a record this time, next time we can no longer carry out the JUnit test, because the record has been deleted, will be error.
    • If we do not use transaction rollback, we need to explicitly restore our additions and deletions to the database operation in the code, will be much more and test-independent code

Method parsing:

    • perform: performs a requestbuilder request , automatically executes the SPRINGMVC process and maps to the appropriate controller execution processing;
    • get: Declares a method that sends a GET request. Mockhttpservletrequestbuilder Get (String urltemplate, Object ... urlvariables): According to the URI template and URI variable is worth a GET request way. Other methods of request, such as post, put, delete, etc. are also provided.
    • param: Add the parameters of request, such as the Pcode = root parameter when sending requests above. If you use the need to send JSON data format will not be able to use this way, can be seen later by @responsebody annotation parameters of the workaround
    • andexpect: Add resultmatcher validation Rules to verify that the results are correct after the controller executes (judging the returned data);
    • anddo: Add Resulthandler result processor, such as printing results to the console when debugging (judging the returned data);
    • Andreturn: Finally, the corresponding Mvcresult is returned, then the custom validation/next asynchronous processing (judgment on the returned data) is performed;

Precautions:

    • Using log4j on Mac is, if you use ${catalina.home} need to be aware that the Mac will not find the path of Tomcat, directly back to the root path "/", and under normal circumstances, the root path is not write permissions, you need to use administrator-assigned permissions.
    • Log4j after the configuration is complete, you need to set the level of the print log, and in JUnit, you will not be able to print the log if it is not set.

3, the back of the background data, it is best to bring our changes to the database results back to the front end.

Why do I need to return a modified or added object in data

    • Returning data to the front end makes it easy to determine whether the data was added or modified successfully
    • Update or add data often need to refresh the page, the data directly to the front end, the front end no longer send a request to get
    • During unit testing, we can audit the data when we are able to perform DDL (add-and-revise) operations on the database, and determine whether our operations are successful. As in the following example:

We send an add operation to add an Softinfo object, the Softinfo class is defined as follows:

public class Softinfo {    private String ID;    private String name;}

After the addition, because we have the unit test transaction rollback , we will not be able to see our additions to the database, we can not determine whether the operation is successful .

In order to solve the above problem, we can add a "data" field in the returned JSON data, parse the data field in the JSON to determine if our add operation was successful. The JSON format is as follows:

{    "status": $,    "data": {"id": "2", "Name": "Test"}}

We can use the Andexpect method to judge the returned data, using "$. Property" To get the data inside, such as I want to get the return data of "Data.name", can be written as "$.data.name". The following example is a data.name= "test" that determines the return.

@Test public    void Testcreateseewoaccountuser () throws Exception {        mockmvc.perform (post ("/users")                        . ContentType (mediatype.application_form_urlencoded)          ). Andexpect (Status (). IsOk ())        . Andexpect (JsonPath ("$ . Data.name ", Is (" Test ")))          . Andexpect (JsonPath (" $.data.createtime ", Notnullvalue ()))        ;    }

Third, the problems encountered

1. Send a parameter that is @responsebody identified, until 400 error. That is, a JSON-formatted data cannot be sent to the controller layer.

Workaround 1:

      Softinfo softinfo = new Softinfo ();
Setting the value
Objectmapper mapper = new Objectmapper (); Objectwriter ow = Mapper.writer (). Withdefaultprettyprinter (); Java.lang.String Requestjson = ow.writevalueasstring (softinfo); String responsestring = Mockmvc.perform (Post ("/softs"). ContentType (mediatype. Application_json). Content (Requestjson)). Anddo (print ()) . Andexpect (Status (). IsOk ()). Andreturn (). GetResponse (). getcontentasstring ();

Solution 2: Use Com.alibaba.fastjson.JSONObject to convert the object to JSON data

Softinfo softinfo = new Softinfo ();//... Set the value String Requestjson = jsonobject.tojsonstring (folderinfo);        String responsestring = Mockmvc.perform (Post ("/softs"). ContentType (Mediatype.application_json). Content ( Requestjson). Anddo (print ())                . Andexpect (Status (). IsOk ()). Andreturn (). GetResponse (). getcontentasstring ();

Note that the above contenttype need to be set to Mediatype.application_json, that is, the declaration is to send the "Application/json" format of the data. Use the content method to place the converted JSON data in the body of the request.

2, Java.lang.noclassdeffounderror:com/jayway/jsonpath/invalidpathexception

The jar package is missing:

Maven dependencies that can be added

<dependency>            <groupId>com.jayway.jsonpath</groupId>            <artifactid>json-path</ artifactid>            <version>0.8.1</version>            <scope>test</scope>        </ dependency>        <dependency>            <groupId>com.jayway.jsonpath</groupId>            < artifactid>json-path-assert</artifactid>            <version>0.8.1</version>            <scope> Test</scope>        </dependency>

Learning Links: https://www.petrikainulainen.net/spring-mvc-test-tutorial/

JUnit test controller (MOCKMVC use), Transfer @requestbody data solution

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.