Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

Spring Boot

Spring Boot is changing the world of Java development with Spring. It is taking away much of the pain that was involved with configuring applications. This is great when you are trying to create what they do by default. They create executable jars by default. What do you have to do if you need to create a WAR file to run on a Tomcat by someone else.

POM file

Let’s start with our project’s pom.xml file. Here we need to define the standard Spring Boot parent starter and also include include the Spring Boot Web starter. The Spring Boot Web starter also includes the Spring Boot Tomcat starter. In our case, we do not want it packaged inside our war because our war file will be deployed on a Tomcat server directly. We don’t have to roll our own. To change this behavior, we include the Spring Boot tomcat starter explicitly and set it’s scope to provided. We also must specify the packaging of our project to be a war.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.javaninja.springboot</groupId>
    <artifactId>springboot-web</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Java Config

Normally the Java Configuration contains a main method because that is how the program will be launched. In this case, we do not need a main method and instead we need to provide a configure method to go along with the SpringBootServletInitializer that we extend.

package com.javaninja.springboot.web;


import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;


@SpringBootApplication
public class WebApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebApplication.class);
    }
}

Example Controller

That is all of the configuration that we need to make this work as a normal Spring MVC controller. To test our functionality, we need a very simple controller, such as the following,.

package com.javaninja.springboot.web;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class ExampleController {

    private Logger log = LoggerFactory.getLogger(getClass());

    @GetMapping("/example/boolean")
    public Boolean exampleBoolean() {
        log.info("Eureka!");
        return true;
    }
}

Test the controller

Let’s create a very simple test using the Spring Boot Test starter. This brings in Junit and MockMvc among other useful APIs.

package com.javaninja.springboot.web;


import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.assertj.core.api.Assertions.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


/**
 * @author norris.shelton
 */
@RunWith(SpringRunner.class)
@WebMvcTest(ExampleController.class)
public class TestExampleController {

    @Autowired
    private MockMvc mvc;

    @Test
    public void testExampleBoolean() {
        try {
            mvc.perform(get("/example/boolean")
                            .accept(MediaType.APPLICATION_JSON))
               .andExpect(status().isOk())
               .andExpect(content().string("true"));
        } catch (Exception e) {
            fail(e.toString());
        }
    }
}

The test run perfectly and produces the following logging and a nice pretty green bar.

2017-07-10 18:36:06.218  INFO 7499 --- [           main] c.j.springboot.web.ExampleController     : Eureka!

July 11th, 2017

Posted In: Maven, MockMVC, Spring, Spring Boot, Spring MVC, Test Driven Development, Unit Tests

Tags: , ,

Leave a Comment

In the previous blog entry titled Turning Spring MVC exceptions into status codes with messages, I mapped exceptions into HTTP status codes.

Test Controller

In this blog we will test those and verify that everything is working correctly. I started with a test controller that I would use to generate the exceptions and the message. I created controller methods that would generate consistent results:

  • ResourceException with an HTTP 400 and a message
  • ResourceException with an HTTP 404 and a message
  • RuntimeException without any developer customization
  • Exception with a message

I wanted to ensure that I had consistent behavior and I was able to pull information from the exception that would be relevant to the client/consumer, but I also wanted to ensure that I never returned a stacktrace to the outside world.

package com.javaninja.cam.spring;


import com.javaninja.cam.dto.Prospect;
import com.javaninja.cam.exception.ResourceException;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {

    @RequestMapping(value = "/test/resourceException400")
    public Prospect getResourceException400() {
        throw new ResourceException(HttpStatus.BAD_REQUEST, "Test Bad Request Exception message");
    }

    @RequestMapping(value = "/test/resourceException404")
    public Prospect getResourceException404() {
        throw new ResourceException(HttpStatus.NOT_FOUND, "Test Not Found Exception message");
    }

    @RequestMapping(value = "/test/runtimeException")
    public int getRuntimeException() {
        return Integer.parseInt("x");
    }

    @RequestMapping(value = "/test/exception")
    public int getException() throws Exception {
        throw new Exception("Test Exception message");
    }
}

Junit Test Class

Once that was written, it was fairly easy to test the results. I used MockMVC with Spring Test to implement my test class. As part of this test, I wanted to ensure that the custom ResourceException that I created was handled correctly. I also wanted to ensure that I could handle RuntimeExceptions that happened during regular program execution could be handled. The last thing I wanted to verify was that developer created and thrown exceptions could be handled and that the message that they were created with was outputted correctly. I checked the HTTP status and the content for each type of exception.

package com.javaninja.cam.spring;


import com.javaninja.cam.JunitTestUtility;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.junit.Assert.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


/**
 * @author norris.shelton
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-test.xml")
@WebAppConfiguration
public class TestCamControllerAdvice {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    /**
     * Needed because we have some legacy code that intereactes directly with the context.  This is NOT normal and 
     * will be removed as the project is modernized. 
     * @throws Exception
     */
    @BeforeClass
    public static void createMockContext() throws Exception {
        JunitTestUtility.setup();
    }

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    /**
     * Tests the custom ResourceException and verifies that it returns a HTTP 400 with the expected message.
     */
    @Test
    public void testResourceException400() {
        try {
            mockMvc.perform(get("/test/resourceException400"))
                   .andExpect(status().isBadRequest())
                   .andExpect(content().string("Test Bad Request Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests the custom ResourceException and verifies that it returns a HTTP 404 with the expected message.
     */
    @Test
    public void testResourceException404() {
        try {
            mockMvc.perform(get("/test/resourceException404"))
                   .andExpect(status().isNotFound())
                   .andExpect(content().string("Test Not Found Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests that a RuntimeException is received and that it returns the expected message.
     */
    @Test
    public void testRuntimeException() {
        try {
            mockMvc.perform(get("/test/runtimeException"))
                   .andExpect(status().isInternalServerError())
                   .andExpect(content().string("java.lang.NumberFormatException: For input string: \"x\""))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests that an Exception is received and that it returns the expected message.
     */
    @Test
    public void testException() {
        try {
            mockMvc.perform(get("/test/exception"))
                   .andExpect(status().isInternalServerError())
                   .andExpect(content().string("Test Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }
}

MockMVC Print Output

For readability, I also displayed the full MockMVC print output. The output makes it very clear that I received the anticipated information and nothing else. The example output is below:

com.javaninja.cam.spring.TestCamControllerAdvice

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/exception
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public int com.twinspires.cam.spring.TestController.getException() throws java.lang.Exception

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = java.lang.Exception

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 500
    Error message = null
          Headers = {Content-Type=, Content-Length=[22]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/resourceException400
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public com.javaninja.cam.dto.Prospect com.javaninja.cam.spring.TestController.getResourceException400()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = com.javaninja.cam.exception.ResourceException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = {Content-Type=, Content-Length=[34]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Bad Request Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/resourceException404
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public com.javaninja.cam.dto.Prospect com.javaninja.cam.spring.TestController.getResourceException404()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = com.javaninja.cam.exception.ResourceException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = {Content-Type=, Content-Length=[32]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Not Found Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/runtimeException
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public int com.javaninja.cam.spring.TestController.getRuntimeException()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = java.lang.NumberFormatException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 500
    Error message = null
          Headers = {Content-Type=, Content-Length=[54]}
     Content type = text/plain;charset=ISO-8859-1
             Body = java.lang.NumberFormatException: For input string: "x"
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

Process finished with exit code 0

There you have it. A full Junit/MockMVC test harness that can be used to determine if a SpringMVC controller is returning the correct information when you are trying to map Exceptions into HTTP status codes, along with messages that can be returned with the client consumer.

November 16th, 2016

Posted In: Java, java ninja, Javaninja, JUnit, MockMVC, Spring, Spring MVC, Test Driven Development

Leave a Comment

I had come up with a Springframework Junit configuration for Spring Batch that worked pretty well. here. This worked pretty well, but I wanted to have the ability to have transactions to rollback my test data for test repeatability. After much tinkering, this is what I have come up with.

Spring Batch Test Maven Dependencies

I added the following dependencies to write the Spring Batch tests.

<dependency>
    <groupId>org.springframework.batch</groupId>
    <artifactId>spring-batch-test</artifactId>
    <version>${spring.batch.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${spring.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

Spring Batch Test Utilities

Spring Batch provides the JobLauncherTestUtils to make it easier to test jobs. The gist of a job test class is:

JobExecution jobExecution = jobLauncherTestUtils.launchJob();

To test a step, you provide the step name to the lanuchStep method.

JobExecution jobExecution = jobLauncherTestUtils.launchStep("step1")

My spring test context defined the JobLauncherTestUtils.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath:applicationContext.xml"/>

    <bean id="jobLauncherTestUtils" class="org.springframework.batch.test.JobLauncherTestUtils"/>
</beans>

Job and Step Test

My Spring Junit test class is fairly simple. This is no different than any other Job or Step test class. NOTE: I was not able to get transactions to work for a Job or a Step.

package com.javaninja.batch;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

/**
 * @author norris.shelton
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TestJobAndStep {

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    @Test
    public void testJob() throws Exception {
        commonAssertions(jobLauncherTestUtils.launchJob());
    }

    @Test
    public void testStep1() throws Exception {
        commonAssertions(jobLauncherTestUtils.launchStep("step1"));
    }

    private void commonAssertions(JobExecution jobExecution) {
        assertNotNull(jobExecution);

        BatchStatus batchStatus = jobExecution.getStatus();
        assertEquals(BatchStatus.COMPLETED, batchStatus);
        assertFalse(batchStatus.isUnsuccessful());

        ExitStatus exitStatus = jobExecution.getExitStatus();
        assertEquals("COMPLETED", exitStatus.getExitCode());
        assertEquals("", exitStatus.getExitDescription());

        List<Throwable> failureExceptions = jobExecution.getFailureExceptions();
        assertNotNull(failureExceptions);
        assertTrue(failureExceptions.isEmpty());
    }
}

Testing Step-scope components

I was able to have more success with transactions when testing Step-scope components like the JPA-related reader and writer. By using the StepScopeTestExecutionListener in combination with TransactionalTestExecutionListener, I was able to get transactions to work correctly.

The JpaPagingItemReader has the following methods that you need to be concerned with:

  • open – opens the output source.
  • read – reads the data.
  • close – closes the entity manager.

The JpaItemWriter provides the write method that handles all of the writing duties, including flushing the data.

The reader and writer test class is:

package com.javaninja.batch;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.item.database.JpaPagingItemReader;
import org.springframework.batch.test.MetaDataInstanceFactory;
import org.springframework.batch.test.StepScopeTestExecutionListener;
import org.springframework.batch.test.StepScopeTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedList;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;

/**
 * @author norris.shelton
 */
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
                         StepScopeTestExecutionListener.class,
                         TransactionalTestExecutionListener.class})
@Transactional
@ContextConfiguration
public class TestReaderAndWriter {

    @Autowired
    private JpaPagingItemReader<CamAffiliateEntity> itemReader;

    @Autowired
    private JpaItemWriter<CamAffiliateEntity> itemWriter;

    @Test
    public void testReader() {
        StepExecution execution = MetaDataInstanceFactory.createStepExecution();
        int count = 0;
        try {
            count = StepScopeTestUtils.doInStepScope(execution, () -> {
                int numStates = 0;
                itemReader.open(execution.getExecutionContext());
                CamAffiliateEntity camAffiliateEntity;
                try {
                    while ((camAffiliateEntity = itemReader.read()) != null) {
                        assertNotNull(camAffiliateEntity);
                        assertNotNull(camAffiliateEntity.getAffiliateId());
                        assertNotNull(camAffiliateEntity.getName());
                        assertNotNull(camAffiliateEntity.getChannelId());
                        numStates++;
                    }
                } finally {
                    try { itemReader.close(); } catch (ItemStreamException e) { fail(e.toString());
                    }
                }
                return numStates;
            });
        } catch (Exception e) {
            fail(e.toString());
        }
        assertEquals(12, count);
    }

    @Test
    public void testWriter() throws Exception {
        List<CamAffiliateEntity> usStateEntities = new LinkedList<>();
        CamAffiliateEntity usStateEntity;
        for (int i = 0; i < 100; i++) {
            usStateEntity = new CamAffiliateEntity();
            usStateEntity.setAffiliateId(i);
            usStateEntity.setName("TEST-DELETE-" + i);
            usStateEntity.setChannelId(13);  // test
            usStateEntities.add(usStateEntity);
        }

        StepExecution execution = MetaDataInstanceFactory.createStepExecution();
        StepScopeTestUtils.doInStepScope(execution, () -> {
            itemWriter.write(usStateEntities);
            return null;
        });
    }
}

Summary

This summary provided me with the ability to run by Spring Batch JPA project for the reader and writer repeatedly without having test data-related problems.

The entire project used to write this blog is located on GitHub sheltonn / spring-batch-jpa

February 19th, 2016

Posted In: hibernate, Integration Tests, Java, java ninja, Javaninja, JUnit, Spring, Spring Batch, Test Driven Development, Unit Tests

Leave a Comment

I had a Springframework-enabled JUnit test that I needed to run multiple times. I thought there used to be a JUnit annotation, but I couldn’t find it. I found and used the Spring @Repeat annotation.

package com.this.and.that;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;

import java.util.concurrent.LinkedBlockingQueue;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners(DependencyInjectionTestExecutionListener.class)
@ContextConfiguration
public class TestCardSet {

    @Repeat(10)
    @Test
    public void testGetShuffledCardQueue() throws Exception {
        LinkedBlockingQueue<Card> cards = CardSet.getShuffledCardQueue();
        assertNotNull(cards);
        assertEquals(52, cards.size());
    }
}

I used to set breakpoints to verify that the test was being ran multiple times. The Spring @Repeat annotation removed the need for this by adding logging.

2014-12-02 09:41:05,499 INFO  o.s.beans.factory.xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [com/iteam/poker/server/model/game/cards/TestCardSet-context.xml]
2014-12-02 09:41:05,815 INFO  o.s.context.support.GenericApplicationContext:510 - Refreshing org.springframework.context.support.GenericApplicationContext@4c6cea8a: startup date [Tue Dec 02 09:41:05 EST 2014]; root of context hierarchy
2014-12-02 09:41:05,866 INFO  o.s.b.factory.support.DefaultListableBeanFactory:598 - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6f7503eb: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
2014-12-02 09:41:05,886 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 1 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,898 INFO  c.i.poker.server.shuffle.SecureShuffleAlgorithm:26 - Cards shuffle algorithm seed has been initialized.
2014-12-02 09:41:05,899 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 2 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,900 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 3 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,901 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 4 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,902 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 5 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,903 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 6 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,903 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 7 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,904 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 8 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,905 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 9 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,906 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 10 of test TestCardSet#testGetShuffledCardQueue()

Process finished with exit code 0

December 2nd, 2014

Posted In: JUnit, Spring, Test Driven Development, Unit Tests

Tags: , , , , ,

One Comment

I have a normal Springframework-enabled project arranged as a Maven project. There were already JUnit tests in the project, along with the requisite Spring configuration.

I needed to add Cucumber tests to the project. I started by adding a cucumber directory to my src/test/java and src/test/resources directories.

I added my feature file in ../src/test/resources/com/cdi/igs/adapter/cucumber/features/Login.feature.

Feature: Login

  @2014w34 @US2422
  Scenario Outline: A lite registered player with email verified should be able submit username and password in the poker client.
  After submission player will see a system message to complete registration and will get re-direct to complete registration step 2 in IGP

    Given my username is "<UserName>"
    And my password is "<Password>"
    And my registration status is "lit"
    And my email verification status is verified as "<email verification status>"
    When I provide my credentials
    Then I should receive the following Poker status "<login result>"
  Examples:
    | UserName | Password   | login result            |email verification status|
    | player1  | Password#1 | AUTH_FAILED_LIT         | 1                       |
  @2014w34 @US2326
  Scenario Outline: A fully registered user should be able to login into the existing poker client. User in examples must be a fully registered user. 0 = SUCCESS, 1 = AUTH_FAILED

    Given my username is "<UserName>"
    And my password is "<Password>"
    And my registration status is "ful"
    When I provide my credentials
    Then I should receive the following Poker status "<Login Result>"
    And I should receive the following demographic data "<First Name>" "<Last Name>" "<Address1>" "<Address2>" "<City>" "<State>" "<Zip>"
    And I should have a third party authentication token

  Examples:
    | UserName | Password   | Login Result | First Name | Last Name | Address1          | Address2 | City     | State | Zip   |
    | player2  | Password#1 | SUCCESS      | Player     | Test      | 1505 Test Address | Apt 100  | New York | NY    | 80000 |


  @2014w34 @US2538
  Scenario Outline: A lite registered user  whose email is not verified will be shown the relevant messaging, and they will be requested to become fully registered
    Given my username is "<UserName>"
    And my password is "<Password>"
    And my registration status is "lit"
    And my email verification status is verified as "<email verification status>"
    When I provide my credentials
    Then I should receive the following Poker status "<login result>"

  Examples:
    | UserName    | Password        |email verification status  | login result             |
    | 8player     | Password!#01    |0                          | AUTH_FAILED_LIT_NO_EMAIL |


  @2014w36 @US2639
  Scenario Outline: Player with existing Password locked status with IGP authentication, cannot login to poker client.

    Given my username is "<UserName>"
    And my password is "<Password>"
    And my person status is "psl"
    When I provide my credentials
    Then I should receive the following Poker status "<login result>"

  Examples:
    | UserName | Password     | login result              |
    | gawky1  | Password#1    | LOCKED_PASSWORD_RESET     |

  @2014w36 @US2629
  Scenario Outline: Player with existing Reset locked status with IGP authentication, cannot login to poker client.

    Given my username is "<UserName>"
    And my password is "<Password>"
    And my person status is "rsl"
    When I provide my credentials
    Then I should receive the following Poker status "<login result>"

  Examples:
    | UserName  | Password      | login result                  |
    | gawky     | Password#1    | LOCKED_CUSTOMER_SERVICE_RESET |

I added my steps file that defines the implementations in …/src/test/java/com/cdi/igs/adapter/cucumber/steps/LoginSteps.java.

package com.cdi.igs.adapter.cucumber.steps;

import com.cdi.igs.adapter.login.LoginRequest;
import com.cdi.igs.adapter.login.LoginResponse;
import com.cdi.igs.adapter.poker.login.PokerLoginService;
import com.cdi.igs.dao.person.Person;
import com.cdi.igs.dao.person.PersonRepository;
import com.cdi.igs.dao.personhasverifiableitem.PersonHasVerifiableItem;
import com.cdi.igs.dao.personhasverifiableitem.PersonHasVerifiableItemRepository;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

/**
 * Login cucumber steps.
 * @author norris.shelton
 */
@ContextConfiguration("classpath:TestCucumber-context.xml")
public class LoginSteps {
    @Autowired
    private PersonRepository        personRepository;
    @Autowired
    private PersonHasVerifiableItemRepository personHasVerifiableItemRepository;
    @Autowired
    private PokerLoginService       pokerLoginService;


    private String     username;
    private String     password;
    private Person     person;
    LoginResponse loginResponse;

    @Given("^my username is "([^"]*)"$")
    public void my_username_is(String username) throws Throwable {
        this.username = username;
    }


    @And("^my password is "([^"]*)"$")
    public void my_password_is(String password) throws Throwable {
        this.password = password;
    }

    @Given("^my registration status is "(.*?)"$")
    public void my_registration_status_is(String registrationStatus) throws Throwable {
        person = personRepository.findByUserName(username);
        assertEquals(registrationStatus, person.getIdRegistrationStatus());
    }



    @Then("^I should receive the following Poker status "(.*?)"$")
    public void i_should_receive_the_following_Poker_status(String responseStatus) throws Throwable {
        assertEquals(responseStatus, loginResponse.getStatus().value());
    }

    @Given("^my email verification status is verified as "(.*?)"$")
    public void my_email_verification_status_is_verified_as(String emailVerificationStatus) throws Throwable {
     List<PersonHasVerifiableItem> personHasVerifiableItemList =
             personHasVerifiableItemRepository.findByIdPersonAndIdVerifiableItemOrderByTimeStampDesc(person.getIdPerson(), "ema");
        if (!personHasVerifiableItemList.isEmpty()) {
            for (PersonHasVerifiableItem emailVerifiableItem : personHasVerifiableItemList) {
                if (emailVerifiableItem.isSuccess()) {
                    assertEquals(person.getIdPerson(),emailVerifiableItem.getIdPerson());
                    break;
                }
            }
        }
    }

    @Given("^my person status is "(.*?)"$")
    public void my_person_status_is(String personStatus) throws Throwable {
        person = personRepository.findByUserName(username);
        assertEquals(personStatus, person.getIdPersonStatus());
    }

    @When("^I provide my credentials$")
    public void I_provide_my_credentials() throws Throwable {
        LoginRequest loginRequest = new LoginRequest();
        loginRequest.setUserId(username);
        loginRequest.setPassword(password);
        loginResponse = pokerLoginService.login(loginRequest);
    }

    @And(
        "^I should receive the following demographic data "([^"]*)" "([^"]*)" "([^"]*)" "([^"]*)" "" +
        "([^"]*)" "([^"]*)" "([^"]*)"$")
    public void I_should_receive_the_following_demographic_data(String firstName,
                                                                String lastName,
                                                                String address1,
                                                                String address2,
                                                                String city,
                                                                String state,
                                                                String zip)
    throws Throwable {
        assertEquals(firstName, StringUtils.trimToEmpty(loginResponse.getFirstName()));
        assertEquals(lastName, StringUtils.trimToEmpty(loginResponse.getLastName()));
        assertEquals(address1, StringUtils.trimToEmpty(loginResponse.getStreetAddress1()));
        assertEquals(address2, StringUtils.trimToEmpty(loginResponse.getStreetAddress2()));
        assertEquals(city, StringUtils.trimToEmpty(loginResponse.getCity()));
        assertEquals(state, StringUtils.trimToEmpty(loginResponse.getIdState()));
        assertEquals(zip, StringUtils.trimToEmpty(loginResponse.getZipCode()));
    }

    @And("^I should have a third party authentication token$")
    public void I_should_have_a_third_party_authentication_token() throws Throwable {
        assertNotNull(StringUtils.trimToNull(loginResponse.getThirdPartyAuthenticationToken()));
    }
}

Now that I have the feature and the steps created, I added in the Cucumber runner in
…/src/test/java/com/cdi/igs/adapter/cucumber/TestCucumber.java. Notice the glue property of @CucumberOptions. That defines directories to scan.

package com.cdi.igs.adapter.cucumber;</code>

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;

/**
* JUnit test class for cucumber.
* @author norris.shelton
*/
@RunWith(Cucumber.class)
@CucumberOptions(
tags = {},
glue = {"com.cdi.igs.adapter.cucumber", "cucumber.api.spring"})
public class TestCucumber {
}

In the top of the LoginSteps class, there was a ContextConfiguration annotation.

@ContextConfiguration("classpath:TestCucumber-context.xml")

That Spring context config file is located in …/src/test/resources/TestCucumber-context.xml and thee contents of that are as follows:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath*:TestAdapter-context.xml"/>
</beans>

It merely says use whatever Spring configuration has already been defined for the rest of the project.

November 20th, 2014

Posted In: Cucumber, Integration Tests, Java, JUnit, Spring, TDD, Test Driven Development, Unit Tests

Tags: , , , , , , , , ,

8 Comments

I have a Springframework integrated Junit test. I had seen annotating a Junit test class with @Test(expected = Exception.class) to test for exceptions before. In this case, we needed to test for Exception and the message was made the difference. This can be accomplished by @Rule

    @Rule
    public ExpectedException expectedEx = ExpectedException.none();

    @Test(expected = Exception.class)
    public void testAddNegativeTransaction() throws Exception {
        expectedEx.expect(Exception.class);
        expectedEx.expectMessage("Cannot withdraw more than available balance.");
        transactionService.addNegativeTransaction(new TransactionRequest("1", "acw", 10, 2000.00));
    }

February 5th, 2014

Posted In: Integration Tests, Java, JUnit, Test Driven Development

Tags: , , , , , , , , , ,

Leave a Comment

LinkedIn Auto Publish Powered By : XYZScripts.com