Saturday, June 18, 2016

Unit testing in Play

Play testing may be done on different levels: unit tests, functional tests, server test etc. - as it is mentioned in Play testing manual. The focus in this post is on writing of unit tests.

Helpers and fakeApplication


Class Helpers is used a lot for unit tests. It imitates a Play application, fakes HTTP requests and responses, session, cookies - all whatever may be needed for tests. A controller under the test should be executed in a context of a Play application. The Helpers method fakeApplication provides an application for running tests. In order to use Helpers and fakeApplication a test class should derive from WithApplication.

The following Helpers API-s should be used:
Helpers.running(Application application, final Runnable block);
Helpers.fakeApplication();

Test with Helpers looks like this:
public class TestController extends WithApplication {
     @Test  
     public void testSomething() {  
         Helpers.running(Helpers.fakeApplication(), () -> {  
             // put test stuff  
             // put asserts  
         });
     }  
}  
Adding import statements for Helpers methods makes code more compact:
import static play.test.Helpers.fakeApplication;
import static play.test.Helpers.running;
...
     @Test  
     public void testSomething() {  
          running(fakeApplication(), () -> {  
               // put test stuff  
               // put asserts  
           });
     }
}  

Testing controllers


Let's call a controller method, which is bound to the particular URL in the routes as a "routed" method. An invocation of a routed method is called a controller action and has a Java type Call.
Play builds so-called reverse route to each action. Call to a reverse route creates an appropriate Call object. This reverse routing mechanism is used for testing controllers.

To invoke a controller action from test the following Helpers API should be used:
Result result = Helpers.route(Helpers.fakeRequest(Call action));

Controller tests example


1. The routes:
GET /conference/:confId    controllers.ConferenceController.getConfId(confId: String)  
POST /conference/:confId/participant controllers.ConferenceController.addParticipant(confId:String) 
2. Generated reverse routes:
controllers.routes.ConferenceController.getConfId(conferenceId) 
controllers.routes.ConferenceController.addParticipant(conferenceId)
3. The method getConfId is bound to GET and does not receive a body in a request. It may be invoked for test with:
Result result = Helpers.route(Helpers.fakeRequest(controllers.routes.ConferenceController.getConfId(conferenceId)));
4. The method addParticipant is bound to POST. It expects to receive a body in a request. Its invocation in test should be done like this:
ParticipantDetails inputData = DataSimulator.createParticipantDetails();
Call action = controllers.routes.ConferenceController.addParticipant(conferenceId);
Result result = route(Helpers.fakeRequest(action).bodyJson(Json.toJson(inputData));

Mocking with PowerMock


To enable mocking a test class should be annotated as following:
 @RunWith(PowerMockRunner.class)
 @PowerMockIgnore({"javax.management.*", "javax.crypto.*"})
 public class TestController extends WithApplication {
    ....

Mocking of a controller action


A controller call is mocked with RequestBuilder:
 RequestBuilder fakeRequest = Helpers.fakeRequest(action); 
For the above addParticipant an action is mocked with:
 RequestBuilder mockActionRequest = Helpers.fakeRequest(controllers.routes.ConferenceController.addParticipant(conferenceId)); 
To invoke the controller method:
 Result result = Helpers.route(mockActionRequest);
The test:
 @Test
 public void testLoginOK() {
     Helpers.running(Helpers.fakeApplication(), () -> {
          ///*whatever mocking*/Mockito.when(...).thenReturn(...);
          RequestBuilder mockActionRequest = Helpers.fakeRequest(
               controllers.routes.LoginController.loginAdmin());
          Result result = Helpers.route(mockActionRequest);
          assertEquals(OK, result.status());
     });
 }

Mocking of an action with JSON body


Let's suppose, that an input is an object of type T.
The action request mocking may be done in several ways.

Option 1:
 public static <T> RequestBuilder fakeRequestWithJson(T input, String method, String url) {  
      JsonNode jsonNode = Json.toJson(input);  
      RequestBuilder fakeRequest = Helpers.fakeRequest(method, url).bodyJson(jsonNode);  
      System.out.println("Created fakeRequest="+fakeRequest +", body="+fakeRequest.body().asJson());  
      return fakeRequest;  
 }  
Option 2:
 public static <T> RequestBuilder fakeActionRequestWithJson(Call action, T input) {  
      JsonNode jsonNode = Json.toJson(input);  
      RequestBuilder fakeRequest = Helpers.fakeRequest(action).bodyJson(jsonNode);  
      System.out.println("Created fakeRequest="+fakeRequest +", body="+fakeRequest.body().asJson());  
      return fakeRequest;  
 }       

Mocking of an action with Base authentication header


The action request mocking:
 public static final String BASIC_AUTH_VALUE = "dummy@com.com:12345";
 public static RequestBuilder fakeActionRequestWithBaseAuthHeader(Call action) {
      String encoded = Base64.getEncoder().encodeToString(BASIC_AUTH_VALUE.getBytes());
      RequestBuilder fakeRequest = Helpers.fakeRequest(action).header(Http.HeaderNames.AUTHORIZATION,
                                                 "Basic " + encoded);
      System.out.println("Created fakeRequest="+fakeRequest.toString() );
      return fakeRequest;
}

Mocking of an action with session


The action request mocking:
 public static final String FAKE_SESSION_ID = "12345";
 public static RequestBuilder fakeActionRequestWithSession(Call action) {
      RequestBuilder fakeRequest = RequestBuilder fakeRequest = Helpers.fakeRequest(action).session("sessionId", FAKE_SESSION_ID);
      System.out.println("Created fakeRequest="+fakeRequest.toString() );
      return fakeRequest;
}
The Play Session class is just an extension of the HashMap<String, String>. It may be mocked with simple code:
 public static Http.Session fakeSession() {  
      return new Http.Session(new HashMap<String, String>());  
 }  

Testing with Guice


See the dedicated post Using Guice for Play tests

Test configuration


Tests may run with a configuration different from an application configuration. See this post how to define a test configuration.

Unit tests execution


See the dedicated post Play unit tests execution

14 comments :

Henning said...

As for Fake Application replacement See https://www.playframework.com/documentation/2.6.x/api/java/play/test/FakeApplication.html
Please keep up the good work.

Ala Schneider said...

Thanks for the feedback.

sandeep saxena said...

I preview this blog. Most of the points are very interesting to read. its help me to study also. Thanks for your help.
core java training in chennai
core java training institutes in chennai
core java Training in Velachery
clinical sas training in chennai
Spring Training in Chennai
QTP Training in Chennai
Manual Testing Training in Chennai

cynthiawilliams said...

Well written post with worthy information. It will definitely be helpful for all. Do post more like this.
Ethical Hacking course in Chennai
Ethical Hacking Training in Chennai
Hacking course
ccna course in Chennai
Salesforce Training in Chennai
Angular 7 Training in Chennai
Web Designing course in Chennai
Ethical Hacking course in Thiruvanmiyur
Ethical Hacking course in Porur
Ethical Hacking course in Adyar

Anbarasan14 said...

I don’t have any idea about commenting on someone’s blog but it’s the first time I really want to appreciate the hard work of this blog admin for sharing this post with us.
Spoken English Classes in Chennai
Best Spoken English Classes in Chennai
IELTS Coaching in Chennai
IELTS Coaching Centre in Chennai
English Speaking Classes in Mumbai
English Speaking Course in Mumbai
IELTS Classes in Mumbai
IELTS Coaching in Mumbai
Spoken English Class in Anna Nagar
IELTS Coaching in T Nagar

Alwin Co Daan said...

I am glad that I saw this post. It is informative blog for us and we need this type of blog thanks for share this blog, Keep posting such instructional blogs and I am looking forward for your future posts.
Cyber Security Projects for Final Year

JavaScript Training in Chennai

Project Centers in Chennai

JavaScript Training in Chennai

priya said...

Great work!
NIce Blog
appium online training
appium training centres in chennai
best appium training institute in chennnai
apppium course
mobile appium in chennnai
mobile training in chennnai
appium training institute in chennnai

priya said...

Have a nice blog
Thank for sharing Information
php online training in chennai
php programming center in chennai
php class in chennnai
php certification course
php developer training institution chennai
php training in chennnai
php mysql course in chennai
php institute in chennnai
php course in chennnai
php training with placement in chennnai
php developer course

mindreader said...

Thanks for the interesting blog that you have implemented here. Very helpful and innovative. Waiting for your next upcoming article.
Java Training in Chennai
Java Training Institute in Chennai
Java course in chennai
Java Training classes
Java Training
Java programming classes
core Java course

devasuresh121@gmail.com said...

I preview this blog. Most of the points are very interesting to read. its help me to study also. Thanks for your help.

7 tips to start a career in digital marketing

“Digital marketing is the marketing of product or service using digital technologies, mainly on the Internet, but also including mobile phones, display advertising, and any other digital medium”. This is the definition that you would get when you search for the term “Digital marketing” in google. Let’s give out a simpler explanation by saying, “the form of marketing, using the internet and technologies like phones, computer etc”.

we have offered to the advanced syllabus course digital marketing for available join now

more details click the link now

https://www.webdschool.com/digital-marketing-course-in-chennai.html

devasuresh121@gmail.com said...

I am glad that I saw this post. It is informative blog for us and we need this type of blog thanks for share this blog, Keep posting such instructional blogs and I am looking forward for your future posts.

Web designing trends in 2020

When we look into the trends, everything which is ruling today’s world was once a start up and slowly begun getting into. But Now they have literally transformed our lives on a tremendous note. To name a few, Facebook, Whats App, Twitter can be a promising proof for such a transformation and have a true impact on the digital world.


we have offered to the advanced syllabus course web design and development for available join now

more details click the link now

https://www.webdschool.com/web-development-course-in-chennai.html

w3webschool said...

Thanks for sharing such a most informative blog.... Waiting for the new updates...

Digital Marketing Course In Kolkata
Web Design Course In Kolkata
SEO Course In Kolkata

adam said...

Thanks for the interesting blog that you have implemented here. Very helpful and innovative. Waiting for your next upcoming article.
Mobile app development training
App development training
Mobile app development course
Mobile development course
Mobile application development course
Learn mobile application development

Vijayakash said...

DevOps Training in Chennai

About the author

My Photo
I trust only simple code and believe that code should be handsome. This is not a matter of technology, but professional approach, consolidated after years of software development. I enjoy to cause things working and feel very happy, when I manage to solve a problem.
Back to Top