I'm trying to write a JUnit test for my Spring module, after seeing that my logic is working using SwaggerUI.
What happens, however, is that I miss some data in my H2 instance (used for the tests only), and I don't understand why.
This is what I'm doing:
MyObjectController.java
#PostMapping("/myobject")
public void save(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Save and get id
Integer id = service.save();
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(id).toUri();
// Run async
service.run(id); // At this stage, id = 1 because the insert completed correctly
// Return id
response.setHeader(HttpHeaders.LOCATION, location.toString());
}
MyObjectService.java
#Async
#Transactional
public void run(Integer id) throws Exception { // As above, id = 1 but this time data is not there!
// Retrieve and run
Optional<MyObject> myObject = myObjectDao.findById(id);
if (!myObject.isPresent()) {
throw new NotFound();
}
...
}
/myobject endpoint is called using MockMVC, and once called it correctly returns the expected id.
If I place a breakpoint at the beginning of service.run(Integer id), and I call /myobject using SwaggerUI, I can see that everything is fine, but this doesn't happen when running in JUnit.
Can you guys please help me with that?
Related
I use HSQLDB for testing purpose. The problem is that when I add some data in init() method, then I can get that data only from the test which did run first.
#Before
public void init() {
if(isRun)
return;
isRun = true;
Role role = new Role();
role.setId(1);
role.setType("User");
roleDAO.save(role);
User user = new User();
user.setCredits(1000);
user.setEmail("User#test.com");
user.setUsername("User");
user.setPassword("qwerty");
user.setRoles(new HashSet<Role>(Arrays.asList(roleDAO.findById(1))));
userDAO.save(user);
User user2 = new User();
user2.setCredits(1000);
user2.setEmail("User2#test.com");
user2.setUsername("User2");
user2.setPassword("qwerty");
user2.setRoles(new HashSet<Role>(Arrays.asList(roleDAO.findById(1))));
userDAO.save(user2);
}
#Test
public void findUserByIdTest() {
User user = userDAO.findByUsername("User");
assertEquals(userDAO.findById(user.getId()), user);
}
#Test
public void addUserTest() {
User user = new User();
user.setCredits(1000);
user.setEmail("Antony#test.com");
user.setPassword("qwerty");
user.setUsername("Antony");
user.setRoles(new HashSet<Role>(Arrays.asList(roleDAO.findById(1))));
userDAO.save(user);
assertEquals(userDAO.findByUsername("Antony"), user);
}
#Test
public void updateUserTest() {
User user = userDAO.findByUsername("User");
user.setCredits(0);
assertEquals(userDAO.findByUsername("User").getCredits(), (Integer) 0);
}
#Test
public void removeUserTest() {
userDAO.remove(userDAO.findByUsername("User"));
assertNull(userDAO.findByUsername("User"));
}
So happens that removeUserTest() method always runs first and when I findAll() data then I see the data I set in init() method. After that, others test methods run but if I do findAll() there, it just returns nothing meaning no data exists.
In addition, I have set hibernate.hbm2ddl.auto=create.
What am I missing here? Why I can get data in the first running method but in others the data just disappears.
It's expected: Spring repository tests are transactional and the transaction is rollbacked at the end of each test by default.
Even if you choose not to rollback, every test should be independant from the others, and should be able to run alone. You should not rely on the execution order either. Your findUserByIdTest() would fail if removeUserTest() runs first.
So, start by cleaning the database and to insert the test data before each test. If you let Spring rollback after each test, cleaning is not necessary, but you should still insert the test data before each test.
Incrementing IDs should not be a problem: you just need to stire the created entities or their IDs in fields of the test, and refer to these entities and their IDs instead of using hard-coded IDs in the test.
I have got a Springboot Application and a Oracle DB with lots of PL/SQL Procedures and these change the state of the DB all the Time.
So now I want to change a loaded entity an want to save it. If the entitystate of the entitymanager and the state of the db is equal everything works fine. But in some cases they are not equal. So if I load an entity and make some changes an druring this a PL/SQL Procedure changes the DB Table. If I save the Entity I will get an Execption of course. So I tried to catch the Exception and then in the catch block I want to refresh the Entity before saving it. But I still get an Exception. Is the Transaction not jet finished? How can I handle this Problem?
I hope the example code explains a little bit.
#RestController
#RequestMapping("/*")
public class FacadeController {
...
#ResponseStatus(HttpStatus.OK)
#RequestMapping( value= "/test4" , method=RequestMethod.GET)
public String test4(){
Unit unit = unitSvice.loadUnit(346497519L);
List<UnitEntry> entries = unit.getEntries();
for (UnitEntry g : entries) {
if (g.getUnitEntryId == 993610345L) {
g.setTag("AA");
g.setVersion(g.getVersion() + 1);
g.setstatus("SaveOrUpdate");
}
}
//<-- DB Table changed entity managed by entitymanger and DB Table
// are no langer equal.
try {
unitSvice.updateUnit(unit , false);
}catch(DataAccessException | IllegalArgumentException e) {
unitSvice.updateUnit(unit , true);
}
...
}
}
#Service("unitSvice")
public class UnitSvice {
#Autowired
private UnitDao repoUnit;
#Transactional
public Unit loadUnit(Long _id) {
Unit unit = repoUnit.findOne(_id);
return unit;
}
#Transactional
public void updateUnit(Unit unit, boolean _withrefrsh ) {
if(_withrefrsh) {
getEntityManager().refresh(unit.getId());
}
repoUnit.save(unit);
}
}
I hope, anyone can help me.
Thanks
yes the problem is ..when you call load all method which is transactional method where entities became detached from session/entitymanager when you are returning from that method.. so,next you are trying to persist detached object. That's why you get exception.
so probably you can use session.update() or session.merge() to save the new update into database.
My method in my rest controller keeps looping.
The method is supposed to get a project from the Mongo database then call another API to get some data and save it again in mongo. It works but it just keeps looping
I use retrofit for my API calls and the application uses spring boot
This is the method that keeps looping
If you need something else just ask me
#RequestMapping(value = "/projects/{id}",method = RequestMethod.PUT)
public void updateCampaign(#PathVariable String id) throws IOException {
Project p = projectRepository.findProjectById(id);
Call<ResponseIndie> get = service.getAllFromCampaign(p.getIndiegogoCampaignId(),API_KEY);
ResponseIndie responseIndie =get.execute().body();
IndiegogoCampaign campaign = responseIndie.getIndiegogoCampaign();
p.setIndiegogoCampaignId(campaign.getId());
p.setIndiegogoCampaign(campaign);
projectRepository.save(p);
logger.info("project saved");
}
I'm quite new to jUnit testing and I'm trying to write some integration test for my Spring Boot application. My plan is to test, whether all mandatory attributes of an object are set. I came up with something like:
#Test(expected = org.springframework.orm.jpa.JpaSystemException.class)
public void testMessageMandatoryAttributes() {
Message corruptedMessage = new Message();
// set id
// corruptedMessage.setId(id);
// set conversation thread
// corruptedMessage.setConversationThread(conversationThread);
messageRepository.save(corruptedMessage);
}
Nevertheless my Message entity has more mandatory attributes...how to test in just one function that all of them are properly set?
Basically you need to test that messageRepository.save(Message) method throws an exception containing some information about missing fields.
Find below a code snippet that may help you to achieve your goal. Replace the assertion in the catch-block with whatever you need to verify.
#Test
public void testMessageMandatoryAttributes() {
Message corruptedMessage = new Message();
// set id
// corruptedMessage.setId(id);
// set conversation thread
// corruptedMessage.setConversationThread(conversationThread);
try {
messageRepository.save(corruptedMessage);
fail();
catch (YourException e) {
assertEquals("Expected value", e.getXxx());
// ...
}
}
If you want to assert exception then I would suggest using ExpectedException. If you want to verify object properties then I would suggest to use write you custom matcher.
I'm trying to run 2 tests with MockMVC (Spring framework).
The first one add a user. When the user is added, an userID is generated, and returned.
The second should delete the added user from this userID.
At the start of my test class, I have this variable: String userID;
Here is the test where I create the user (it works). After creating the user, I get from the response the generated ID for this user.
#Test
public void it_adds_a_new_user() throws Exception {
MvcResult result = mockMvc
.perform(post("/users")
.contentType(MediaType.APPLICATION_JSON)
.content("User infos, in JSON..."))
.andExpect(status().isOk())
.andReturn();
//Next lines just take the ID from the response
Matcher matcher = Pattern.compile("\\d+").matcher(result.getResponse().getContentAsString());
matcher.find();
this.userID = matcher.group();
System.out.println(userID); //Correctly print the generated ID
}
Now, I try to delete this poor guy:
#Test
public void it_deletes_the_new_user() throws Exception {
System.out.println(userID); //It prints null!
mockMvc.perform(delete("/users/" + userID)
.contentType(MediaType.APPLICATION_JSON)
.andExpect(status().isOk()); //400 because userID is null :-(
}
The problem is that userID is correctly initialized in the first test, but is null in the second (it is a class variable). I don't understand why.
Can you help me running those tests, and if possible explain me why userID == null on my second test ?
Thanks!
create getter and setter method for set and get the value userID like:
void setUserId(matcher.group())---->should be inside it_adds_a_new_user()
now you have setted the userId
add one gette method also,
get the value by calling getUserId()----->should be inside it_deletes_the_new_user()
since i dont know the structuer of your program so giving you just an idea to solve you problem.