Spring Controller Test - model().attribute java.lang.AssertionError - spring

I have a controller which I try to test and I have a problem with .andExpect(model().attribute...
I always get an error: java.lang.AssertionError.
I tried
.andExpect(model().attribute("voivodeships", voivodeships))
.andExpect(model().attribute("voivodeships", Matchers.hasItemInArray(Matchers.<Voivodeship> hasProperty("name", Matchers.equalToIgnoringCase("Lodzkie")))))
and both return an java.lang.AssertionError even though the data passed is correct
Why is it happening? Is there any workaround?
#Test
void getVoivodeshipTest() throws Exception {
List<Voivodeship> voivodeships = voivodeshipService.findAll();
when(voivodeshipService.findAll()).thenReturn(voivodeships);
mockMvc.perform(get("/taxoffice", voivodeships)
.accept(MediaType.APPLICATION_JSON)
.content(new Gson().toJson(voivodeships)))
//.andExpect(model().attribute("voivodeships", voivodeships))
//.andExpect(model().attribute("voivodeships", hasProperty("name", is("Łódzkie"))))
.andExpect(model().attribute("voivodeships", Matchers.hasItemInArray(Matchers.<Voivodeship> hasProperty("name", Matchers.equalToIgnoringCase("Łódzkie")))))
.andExpect(view().name("taxoffice"))
.andExpect(model().hasNoErrors())
.andDo(print())
.andExpect(status().isOk());
}
Error 1:
java.lang.AssertionError: Model attribute 'voivodeships' Expected: an array containing hasProperty("name", a string equal to "Lodzkie"
ignoring case)
but: was a java.util.ArrayList (<[com.walidatorpnr.taxoffice.Voivodeship#e302b72e,
com.walidatorpnr.taxoffice.Voivodeship#f7016ea8,
com.walidatorpnr.taxoffice.Voivodeship#a4c57aec,
com.walidatorpnr.taxoffice.Voivodeship#4a146c7f,
com.walidatorpnr.taxoffice.Voivodeship#1db365fc,
com.walidatorpnr.taxoffice.Voivodeship#cae5bdc9]>)
Error 2:
java.lang.AssertionError: Model attribute 'voivodeships'
expected:<[com.walidatorpnr.taxoffice.Voivodeship#fa379eee,
com.walidatorpnr.taxoffice.Voivodeship#f2dac6d5,
com.walidatorpnr.taxoffice.Voivodeship#2d24bceb,
com.walidatorpnr.taxoffice.Voivodeship#e0160815,
com.walidatorpnr.taxoffice.Voivodeship#ab4bcec0,
com.walidatorpnr.taxoffice.Voivodeship#10adc72d]> but
was:<[com.walidatorpnr.taxoffice.Voivodeship#ff790ce9,
com.walidatorpnr.taxoffice.Voivodeship#f7ea15d1,
com.walidatorpnr.taxoffice.Voivodeship#5a6e5a2b,
com.walidatorpnr.taxoffice.Voivodeship#bf5e8489,
com.walidatorpnr.taxoffice.Voivodeship#c08d9b80,
com.walidatorpnr.taxoffice.Voivodeship#cdd602ec]> Expected
:[com.walidatorpnr.taxoffice.Voivodeship#fa379eee,
com.walidatorpnr.taxoffice.Voivodeship#f2dac6d5,
com.walidatorpnr.taxoffice.Voivodeship#2d24bceb,
com.walidatorpnr.taxoffice.Voivodeship#e0160815,
com.walidatorpnr.taxoffice.Voivodeship#ab4bcec0, com. ...
Actual :[com.walidatorpnr.taxoffice.Voivodeship#ff790ce9,
com.walidatorpnr.taxoffice.Voivodeship#f7ea15d1,
com.walidatorpnr.taxoffice.Voivodeship#5a6e5a2b,
com.walidatorpnr.taxoffice.Voivodeship#bf5e8489,
com.walidatorpnr.taxoffice.Voivodeship#c08d9b80, com. ...
Controller.java
#GetMapping("/taxoffice")
public String getVoivodeship(Model model) {
List<Voivodeship> voivodeships = voivodeshipService.findAll();
model.addAttribute("voivodeships", voivodeships);
return "taxoffice";
}

Related

how to return a specific status code in Kotlin

I've set up a route that when I get a name in my post body I will search the DB and return an ID value.
What I want to do is once there is no ID present in the DB return a 204 status code.
But should that be handled in the service or in my controller?
and
How do I return my specific status code?
#ResponseStatus(HttpStatus.OK)
#PostMapping("/ID_values/")
fun getID(
#RequestBody
name: String
): ResponseEntity<String> = ResponseEntity.ok(IDLookupService.lookupIDValue(name))
}
#Service
class EmailLookupService(
private val IDRepo: IDRepo
) : Logging {
fun lookupIDValue(name: String): String {
val IDLookupResult = IDRepo.findById(name)
return if (IDLookupResult.isPresent) {
IDLookupResult.get().ID.toString()
} else {
// return status code 204
}
}
}
First, you should omit the #ResponseStatus(HttpStatus.OK) annotation if you do not wish to always return a status code of 200. Using that annotation, it would suffice to only specify the response body as return value (i.e specify return type String and then return only result in your example), and Spring would automatically wrap that into a response entity with HTTP-status OK.
Second, you need some way to tell the caller of IDLookupService.lookupIDValue (which should probably be called on an instance of IDLookupService and not the class itself) that there was nothing found. This could be done for instance by changing the return type to String? and return null if nothing was found.
Then you can change getID to return
val result = idLookupService.lookupIDValue(name)
return if(result != null) ResponseEntity.ok(result)
else ResponseEntity("not found", HttpStatus.NO_CONTENT)
If you wish to return something different than a String in the case there was nothing found (like an error object with detailed information; in the example here it is simply the text "not found"), you can change the response type of getID to ResponseEntity<*>.

call private method (PowerMockito Test)

First a save() method is executed which passes the test until it reaches a condition, where if it is true it calls the saveBankAccountAndRole() method and if it is false it sends a Mono.error(new Exception("...").
The sizeAccounts(String customerId) method does pass the test.
In the saveBankAccountAndRole(BankAccountDto bnkDto) method, after executing the sizeAccounts() method, the test does not pass, what am I missing?
public Flux<BankAccountDto> findAccountsByCustomerId(String customerId) {
return mongoRepository
.findAll()
.filter(ba ->
ba.getCustomerId().equals(customerId))
.map(AppUtils::entityToDto);
}
private Mono<Long> sizeAccounts(String customerId){
return findAccountsByCustomerId(customerId)
.count();
}
private Mono<BankAccountDto> saveBankAccountAndRole(BankAccountDto bnkDto) {
return sizeAccounts(bnkDto.getCustomerId())
.flatMap(number -> {
bnkDto.setOpeningOrder(number + 1);
return mongoRepository.save(AppUtils.dtoToEntity(bnkDto))
.switchIfEmpty(Mono.error(new Exception("Problem saving the bank account")))
.zipWhen(bnk -> {
var customerRoleDto = new CustomerRoleDto();
customerRoleDto.setBankAccountId(bnk.getBankAccountId());
customerRoleDto.setCustomerId(bnkDto.getCustomerId());
customerRoleDto.setRoleType(bnkDto.getRoleType());
return webClientRoleHelper.saveCustomerRole(customerRoleDto);
})
.switchIfEmpty(Mono.error(new Exception("Problem saving roles")))
.map(tuple -> AppUtils.entityToDto(tuple.getT1()));
});
}
test:
#Mock
private IMongoBankAccountRepository mongoRepository;
#InjectMocks
private BankAccountServiceImpl bankAccountServiceImpl;
#Test
void saveBankAccountAndRoleTest() throws Exception {
when(mongoRepository.findAll()).thenReturn(Flux.just(bnkDto)
.map(AppUtils::dtoToEntity));
when(mongoRepository.findAll().filter(ba ->
ba.getCustomerId().equals(customerId)))
.thenReturn(Flux.just(bnkDto).map(AppUtils::dtoToEntity));
StepVerifier.create(bankAccountServiceImpl.findAccountsByCustomerId(customerId))
.expectSubscription()
.expectNext(bnkDto)
.verifyComplete();
var spy = PowerMockito.spy(bankAccountServiceImpl);
PowerMockito.when(spy, "sizeAccounts", customerId)
.thenReturn(Mono.just(2L));
PowerMockito.when(spy, "saveBankAccountAndRole",bnkDto)
.thenReturn(Mono.just(bnkDto));
}
exception:
java.lang.AssertionError: expectation "expectNext(com.nttdata.bootcamp.model.dto.BankAccountDto#147c4523)" failed (expected value: com.nttdata.bootcamp.model.dto.BankAccountDto#147c4523; actual value: com.nttdata.bootcamp.model.dto.BankAccountDto#551725e4) at com.nttdata.bootcamp.business.impl.BankAccountServiceImplTest.saveBankAccountAndRoleTest(BankAccountServiceImplTest.java:267)
Which sends me when verifyComplete()
By looking at the code in your test, you shouldn't expect an specific object to be returned.
when(mongoRepository.findAll()).thenReturn(Flux.just(bnkDto)
.map(AppUtils::dtoToEntity));
when(mongoRepository.findAll().filter(ba ->
ba.getCustomerId().equals(customerId)))
.thenReturn(Flux.just(bnkDto).map(AppUtils::dtoToEntity));
The code above is mapping that DTO object to an Entity, which makes sense for a repository. However, that means that the following piece of code will "remap" it to a newly created object:
.zipWhen(bnk -> {
var customerRoleDto = new CustomerRoleDto();
customerRoleDto.setBankAccountId(bnk.getBankAccountId());
customerRoleDto.setCustomerId(bnkDto.getCustomerId());
customerRoleDto.setRoleType(bnkDto.getRoleType());
return webClientRoleHelper.saveCustomerRole(customerRoleDto);
})
Thus, you should be expecting an object with that same class, containing the same instance's variables values. But you can't expect it to be the exact same object.
You might want to try this (untested code):
StepVerifier.create(bankAccountServiceImpl.findAccountsByCustomerId(customerId))
.expectSubscription()
.expectMatches(dto -> dto.getBankAccountId().equals(bankDto.getBankAccountId) && dto.getCustomerId.equals(bnkDto.getCustomerId))
.verifyComplete();
I hope that works out for you.

Spring boot: mockMvc testing controller: Expected: Entity, Actuall: null

How looks my json:
event object
{
...
"game": {
//game fields
}
}
...
}
I am trying to do:
event.setGame(new Game());
And check if there is my value by mockMvc
.andExpect(jsonPath("$.game").value(event.getGame()))
But i am getting error:
java.lang.AssertionError: JSON path "$.game"
Expected : Event(id= null, name= null, ...)
Actual :null
Why i am getting null, if i should get just empty game?
P.S. even if i set fields to game, i will get null
I make .andDo(print), and get :
Body = // event
{
"id":"5f087eec-8bf0-11eb-8dcd-0242ac130003",
"game":
{
"id":null,
"team1":null,
"team2":null,
"gameDate":null,
},
"user":
{
//user fields
}
}
How looks controller:
#GetMapping("/{id}")
public ResponseEntity<GetEventById> getEventById #PathVariable("id") String id) {
GetEventByIResponse dto= service.getEventById(id);
return ResponseEntity
.status(HttpStatus.OK)
.body(dto);
}
In my test i am creating GetEventByIResponse, how it looks:
public class Event {
private String id;
private Game game;
...
}
The JsonPath assert works as follows:
It first parses the path result into a Map/List/Object, to see if the origin was an array/object/simple type.
Then, if it's a Map (like in your case) it tries to parse the path result into the same type as the expected object.
Finally it compare the created object to the expected object using equals().
In your case I see several problems:
The AssertionError talks about an Event although you seem to hand in a Game.
We do not know if the serialization/deserialization works at all
Maybe you should try one of the following:
Place a breakpoint right here to watch the assert steps in your debugger:
Start with simple type comparisons:
.andExpect(jsonPath("$.id").value("foo"))
.andExpect(jsonPath("$.game.id").value("bar"))
Seems like the json path referencing the game child object is incorrect, try below:
.andExpect(jsonPath("$.event.game").value(event.getGame()))

Strange TestNg DataProvider MethodMatcherException

The DataProvider returns exactly the number and type of arguments required by the method.
This error is strange because if I substitute change the parameter and argument to use List<Experiment> instead of an Experiment[] then no exception is raised.
The method is:
#Test(dataProvider = "provideExperimentId")
public void testDetermineExperimentId(Experiment[] experiments, int experimentId, int expected)
{
mockExperimentId(experiments, experimentId)
assertEquals(fileParser.determineExperimentId(), expected);
}
The mockExperimentId(Experiment[], int) method sets up some when-then clauses,
and uses the parameters to customise some return values.
The data provider is:
#DataProvider
private Object[][] provideExperimentId(){
MockitoAnnotations.initMocks(this);
return new Object[][]{
{new Experiment[]{mockedExperiment}, 1, 1}
};
}
For some reason, I get the following mismatch exception, even though the number of arguments and the types are in agreement.
org.testng.internal.reflect.MethodMatcherException:
Data provider mismatch
Method: testDetermineExperimentId([Parameter{index=0, type=[Lcom.redacted.Experiment;, declaredAnnotations=[]}, Parameter{index=1, type=int, declaredAnnotations=[]}, Parameter{index=2, type=int, declaredAnnotations=[]}])
Arguments: [([Lcom.redacted.Experiment;) [mockedExperiment],(java.lang.Integer) 1,(java.lang.Integer) 1]
at org.testng.internal.reflect.DataProviderMethodMatcher.getConformingArguments(DataProviderMethodMatcher.java:45)
at org.testng.internal.Parameters.injectParameters(Parameters.java:796)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:973)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
at org.testng.TestRunner.privateRun(TestRunner.java:648)
at org.testng.TestRunner.run(TestRunner.java:505)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
at org.testng.SuiteRunner.run(SuiteRunner.java:364)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1187)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1116)
at org.testng.TestNG.runSuites(TestNG.java:1028)
at org.testng.TestNG.run(TestNG.java:996)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)
However, changing the method and DataProvider to use a list raises no exception
#Test(dataProvider = "provideExperimentId")
public void testDetermineExperimentId(List<Experiment> experiments, int experimentId, int expected)
{
mockExperimentId(experiments.toArray(new Experiment[0]), experimentId)
assertEquals(fileParser.determineExperimentId(), expected);
}
The mockExperimentId(Experiment[], int) method sets up some when-then clauses,
and uses the parameters to customise some return values
#DataProvider
private Object[][] provideExperimentId(){
MockitoAnnotations.initMocks(this);
return new Object[][]{
{Arrays.asList(mockedExperiment), 1, 1}
};
}

Sax XML Parser, switch does not take a string

We are trying to parse an xml file using sax parser, but we faced a problem using switch in :
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
switch(MyEnum.valueOf(qNam))
case tag1:
.......
break;
case tag2:
........
break;
case tag5:
..........
In each case we are populating some pojo objects.
The problem is when the parser encounter a tag that we are ignoring it throw an exception.
Exception is thrown because your own code calls MyEnum.valueOf with argument that is not guaranteed to be name of enum constant.
Because you want to ignore Exception, it is likely better to not have exception thrown at all. That can be done for example by adding following method to MyEnum:
public static boolean isOneOfTheValues(String val) {
for (MyEnum m: values()) {
if (m.name().equals(val)) {
return true;
}
}
return false;
}
and then not going in to switch statement at all if it is known to be unknown value:
if (!MyEnum.isOneOfTheValues(s)) {
return;
}
switch(MyEnum.valueOf(qNam))
If enumeration contains many constants, using rebuild set instead of iterating over return value of values() can provide better performance.

Resources