0

Setup: spring-boot 1.4.3.RELEASE Java 1.8

I've written three test cases against my BluecostRestController.java (code below). The tests for the following URLs worked fine: GET /bluecost/sscdata GET /bluecost/sscdata/sergio

Now I'm trying to write a test case for the POST /bluecost/sscdata/ and I am getting the following Assertion Exception:

java.lang.AssertionError: Status expected:<201> but was:<400>
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54)
    at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81)
    at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:665)
    at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
    at com.ibm.cio.cloud.cost.spreadsheet.controller.UTBlueCostRestControllerTests.testAddingSpreadsheetUpload(UTBlueCostRestControllerTests.java:198)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

For some reason it's not finding this path: /bluecost/sscdata with that object. Here is my test class:

@RunWith(SpringRunner.class)    @WebMvcTest(com.ibm.cio.cloud.cost.spreadsheet.rest.controller.BlueCostRestController.class)   
    public class UTBlueCostRestControllerTests extends UTBlueCostRestControllerParent {

        private static final long CREATED_SSCDATA_ID = 400l;

        @Test    
        public void testAddingSpreadsheetUpload() throws Exception {

            BluecostSSCData mockSSCData = new BluecostSSCData(
                    CREATED_SSCDATA_ID,
                    200l,
                    "chargeType-D7",
                    "controlGroup-293D",
                    "TEXACO",
                    "TestUser"
                    );

            String sscData = "{\r\n" + 
                    "   \"sscdataid\": \"400\",\r\n" + 
                    "   \"processGroupId\": \"200\",\r\n" + 
                    "   \"chargeTypeCd\": \"chargeType-D7\",\r\n" + 
                    "   \"controlGroupCd\": \"controlGroup-293D\",\r\n" + 
                    "   \"accountId\": \"TEXACO\",\r\n" + 
                    "   \"userId\": \"TestUser\",\r\n" + 
                    "}";

            when(blueCostSSCDataService.saveBluecostSSCData(mockSSCData))
                            .thenReturn(mockSSCData);

            mvc.perform(MockMvcRequestBuilders
                    .post("/bluecost/sscdata/").content(sscData)
                    .contentType(MediaType.APPLICATION_JSON))
                    .andExpect(status().isCreated())
                    .andExpect(header().string("location",
                            containsString("/bluecost/sscdata/"
                                    + CREATED_SSCDATA_ID)));

        }   

This is the Controller Class:
    @RequestMapping("bluecost")
    @RestController
    public class BlueCostRestController {

        @Autowired
        BluecostSSCDataService blueCostSSCDataService;

        @Autowired
        CostSpreadsheetService costSpreadsheetService;

        @Autowired
        BlueCostService blueCostService;

        @RequestMapping(value = "/sscdata/", method = RequestMethod.GET)
        public ResponseEntity<List<BluecostSSCData>> getAllBluecostSSCData() {
            List<BluecostSSCData> bluecostSSCDataList = blueCostSSCDataService.getAllBlueCostSSCData();
            if (bluecostSSCDataList.isEmpty()) {
                return new ResponseEntity(HttpStatus.NO_CONTENT); 
            }
            return new ResponseEntity<List<BluecostSSCData>>(bluecostSSCDataList, HttpStatus.OK);
        }

        @RequestMapping(value = "/sscdata/{localField2}", method = RequestMethod.GET)
        public ResponseEntity<?> findSSCDataByUploader(@PathVariable("localField2") String localField2) {

            List<BluecostSSCData> bluecostSSCDataList = blueCostSSCDataService.findBluecostSSCDataByUploader(localField2);
            if (bluecostSSCDataList.size() == 0) {
                return new ResponseEntity(HttpStatus.NOT_FOUND);
            }
            return new ResponseEntity<List<BluecostSSCData>>(bluecostSSCDataList, HttpStatus.OK);
        }

        @RequestMapping(value = "/sscdata/", method = RequestMethod.POST)
        public ResponseEntity<?> createBluecostSSCData(@RequestBody BluecostSSCData sscdata) {

            BluecostSSCData createdSSCData = blueCostSSCDataService.saveBluecostSSCData(sscdata);

            if (createdSSCData == null)
                return ResponseEntity.noContent().build();

            URI location = ServletUriComponentsBuilder
                    .fromCurrentRequest().path("/{id}")
                    .buildAndExpand(createdSSCData.getSscdataid())
                    .toUri();

            return ResponseEntity.created(location).build();

        }
VedantK
  • 9,728
  • 7
  • 66
  • 71
JamesD
  • 679
  • 10
  • 36
  • It is finding the path, otherwise you'd get a 405 or 404 error. HTTP 4xx status codes indicates that something went wrong at the client-side. It's likely that the framework failed to parse the `@RequestBody`. And the reason to that could be the trailing comma at the `"userId": "TestUser",` Try removing it, let me know if it works – alegria Jun 28 '18 at 04:11

1 Answers1

0

As suggested by @dashboard this could be issue with trailing comma in "userId": "TestUser". However, such mistake are likely to happen because of copy-paste. To write such junit I preferred to build json string using JSONObject instead of writing manually.

So, your String sscData = "{\r\n" + .... would be represent as,

import org.json.JSONObject;

JSONObject json = new JSONObject();
json.put("sscdataid", 400);
json.put("chargeTypeCd", controlGroup-293D);
...

And your post call become,

mvc.perform(MockMvcRequestBuilders
     .post("/bluecost/sscdata/").content(**json.toString()**)
     .contentType(MediaType.APPLICATION_JSON))

Hope this helps.

Shaunak Patel
  • 1,581
  • 11
  • 14
  • I removed the comma from the hand-coded JSON string, it still produced the same error. Moving on to the 2nd recommendation by Shaunak. – JamesD Jun 28 '18 at 13:26
  • OK - the JSONObject creation improved things. Now I'm getting 204 (No content) instead of 400. For some reason the mock service is returning NULL instead of the created object. Not sure why... – JamesD Jun 28 '18 at 13:45
  • > the mock service is returning NULL can you point me in your code base? – Shaunak Patel Jun 28 '18 at 13:50
  • when(blueCostSSCDataService.saveBluecostSSCData(mockSSCData)) .thenReturn(mockSSCData); - I think something is going on in this code... – JamesD Jun 28 '18 at 14:35
  • try(not sure but I don't see any reason to fail) @Mock BluecostSSCDataService blueCostSSCDataService; when(blueCostSSCDataService.saveBluecostSSCData(Mockito.any(BluecostSSCData.class))).thenReturn(mockSSCData); – Shaunak Patel Jun 28 '18 at 15:39
  • IT WORKED! Thank you very much Shaunak. – JamesD Jun 28 '18 at 17:18
  • Please accept and vote up(if my answer helps you a lot) :) – Shaunak Patel Jun 28 '18 at 17:30