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.
Related
I am trying to make a test for the method to delete an entity by id. I've written the test for the case when an entity with the given id doesn't exist, but in case when the entity exists, I'm apparently doing something wrong. This is the delete method from the service. I'm using the deleteById() method of the JpaRepository.
public void deleteById(Integer id) {
Optional<Agency> optionalAgency = repo.findAll().stream()
.filter(agency -> agency.getId().equals(id))
.findFirst();
if (optionalAgency.isPresent()) {
repo.deleteById(optionalAgency.get().getId());
} else {
throw new AgencyNotFoundException("Agency not found");
}
}
And this is my test:
#Mock
private AgencyRepository agencyRepository;
#Mock
private AgencyMapper mapper;
#InjectMocks
private AgencyService agencyService;
#Test
void delete() {
Agency agency = new Agency();
when(agencyRepository.findById(1)).thenReturn(Optional.of(agency));
agencyService.deleteById(1);
verify(agencyRepository).deleteById(1);
}
What assertion should I make in order to verify that the deletion was successful? The way I've tried it it doesn't work, the result of the test is that an exception is thrown. I'm guessing that the exception is thrown because agencyRepository.findById((int) 1L); basically doesn't exist anymore, but I thought maybe there's a better way to verify the deletion, without searching for the deleted object.
Not the answer, but your method could be written something like this:
public void deleteById(Integer id) {
Agency agency = repo.findById(id).orElseThrow(() -> throw new AgencyNotFoundException("Agency not found"));
repo.deleteById(agency.getId());
}
Because:
Optional<Agency> optionalAgency = repo.findAll().stream().filter(agency -> agency.getId().equals(id)).findFirst(); is not efficient. What if you have thousands of agencies? Will you fetch all and filter through all of them just to find by id. You have that method in your repository already.
if (optionalAgency.isPresent()) {} Optional.isPresent is not good practise. Read here and this answer
repo is a mock, so calling deleteById on it won't actually delete anything. Instead, you could verify that calling the AgencyService's deleteById actually calls AgencyRepository's deleteById.
EDIT:
The repository's code uses findAll, not findById, so you need to make sure you mock that:
#Test
void delete() {
Agency agency = new Agency();
agenct.setId((int) 1L);
when(agencyRepository.findAll()).thenReturn(Collections.singletonList(agency));
agencyService.deleteById((int) 1L);
verify(agencyRepository).delteById((int) 1L);
}
I'm looking for a way to keep my component tests self contained.
So to achieve this behavior, in some of the tests I need to have a 'clean database' or at least a 'clean table'. I still couldn't find a way to do this inside a testcontainer.
So here is what I've tried so far:
My container setup class:
public class PostgreSqlTestContainer implements QuarkusTestResourceLifecycleManager {
public static final PostgreSQLContainer<?> POSTGRES = new PostgreSQLContainer<>("postgres:alpine");
#Override
public Map<String, String> start() {
POSTGRES.start();
return some_db_config_as_per_doc;
}
#Override
public void stop() {
POSTGRES.stop();
}
Here is the tests class:
#QuarkusTest
#QuarkusTestResource(PostgreSqlTestContainer.class)
class UserResourcesTest {
#Test
scenario_one(){
// create a new user
// do some stuff (#POST.. check HTTP == 201)
}
#Test
scenario_two(){
// create new user
// do some stuff (#POST.. check HTTP == 201) (pass)
// look for all users on database
// do more stuff (#GET.. check HTTP == 200) (pass)
// assert that only 1 user was found
// since scenario_one should not interfere with scenario_two (fail)
}
}
The second scenario fails since some 'dirty' from the first test was still on the db container.
I've tried to stop/start the container for each test. (very, very slow process, and sometimes I get an error, and very slow again).
#BeforeEach
void setup(){
PostgreSqlTestContainer.POSTGRES.stop();
PostgreSqlTestContainer.POSTGRES.start();
}
Also tried to truncate the table / drop the whole db:
#Inject
EntityManager entityManager;
#BeforeEach
private void rollBack(){
truncate();
}
void truncate(){
Query nativeQuery = entityManager.createNativeQuery("DROP DATABASE IF EXISTS db_name");
nativeQuery.executeUpdate();
}
I'm looking for any workaround for this problem, I just want to somehow use a #BeforeEach to clean up the DB before each test. I mean, all I want is a clean environment for each test.
Create a template test database with the name test_template.
After each test,
disconnect all sessions from the test database (not required with PostgreSQL v13):
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'test';
drop the database with
DROP DATABASE test;
In v13, use the additional FORCE option.
create a new test database with
CREATE DATABASE test TEMPLATE test_template;
Note: you have to enable autocommit in the JDBC driver for CREATE DATABASE and DROP DATABASE to work.
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.
EDIT: replaced 'retrieve.name == "name1"' by 'retrieve.name.equals("name1")'.
EDIT2: Added #BeforeClass and #AfterClass (credit: http://digitalsanctum.com/2012/06/01/play-framework-2-tutorial-ebean-orm/).
I'm writing JUnit tests for a play web app and for some odd reason I can't seem to modify the database entries. Here's the simplest example I could come up with that illustrates the problem:
#BeforeClass
public static void setup() throws IOException {
app = Helpers.fakeApplication(Helpers.inMemoryDatabase());
Helpers.start(app);
server = Ebean.getServer("default");
ServerConfig config = new ServerConfig();
config.setDebugSql(true);
ddl = new DdlGenerator((SpiEbeanServer) server, new H2Platform(), config);
// drop
String dropScript = ddl.generateDropDdl();
ddl.runScript(false, dropScript);
// create
String createScript = ddl.generateCreateDdl();
ddl.runScript(false, createScript);
}
#AfterClass
public static void stopApp() {
// drop
String dropScript = ddl.generateDropDdl();
ddl.runScript(false, dropScript);
Helpers.stop(app);
}
#Test
public void UserModify(){
// create user (User extends Model)
User user = new User();
user.id = (long) 1;
user.name = "name1";
user.save();
// modify
user.name = "name2";
user.update();
user.save();
// look-up
User retrieve = User.find.byId((long) 1);
assertFalse("Old name", retrieve.name.equals("name1"));
}
Needless to say this should pass, but it doesn't... I know you can use "update()" to change database fields, because someone else on the project says he uses it like that and it works.
Play Framework documentation: http://www.playframework.com/documentation/2.1.1/Home
Any ideas why this test fails?
This is happening because of a problem in Play Framework.
Play doesn't enhance code in "test" folder, only in "app" folder.
Because of that getters and setters are not generated, and Ebean is relying on setters to detect that object is dirty and to support lazy loading. This way in your case Ebean doesn't know that property was updated on object.
As a simple solution, you can create getters and setters yourself. Also, that seems to be fixed already and probably should be included in next Play release: https://github.com/playframework/Play20/blob/master/framework/test/integrationtest-java/test/models/EbeanEnhancementTest.java
Here's a simple Play project with User model and working test: https://github.com/pharod/so-play2-issue1
See more details on getters and setters generation by Play here, in "Caveats" section near bottom of page: http://www.playframework.com/documentation/2.1.1/JavaEbean
As others have stated, you should use .equals() for string equality.
But the main problem is that to run this kind of tests (accessing the database) You need a running application.
In play, this could be done, by running a fake application with the test. Check out this guide:
http://www.playframework.com/documentation/2.0/JavaTest
I need to make a JUnit test that checks whether it is possible to delete something from the database. I'm using the Play 2.1 Framework with an in-memory database.
I tried assertNull(...), but that failed. I then tried assertNotNUll(...) and the test passes, but I'm not sure this is the best way to do it or that it can even confirm deletion. Is there a better way to check if an item has been deleted? Should I look up the object and expect an error?
Here's my code (I also have some #BeforeClass and #AfterClass code, but it's no relevant to my question):
#Test
public void UserDelete(){
// Test ID: 3
// creating a new user
User user = new User();
user.id = (long) 4;
user.facebookId = "0000004";
user.email = "test4#gmail.com";
user.name = "name4";
user.save();
// deleting the user
user.delete();
// checking deletion
assertNotNull(user);
}
In general you usually have to do something like this. Of course this is a crude example but it points out that you should use some persistence solution like JPA to persist your domain objects.
#Test(expected = WhateverObjectNotFoundException.class)
public void removeUserTest(){
User u = UserFactory.createTestUser();
Long id = myEntityManager.persist(u);
assertNotNull(id);
myEntityManager.remove(u);
myEntityManager.findById(id);
}
In my opinion the User shouldn't be responsible for its lifecycle since it does not make sense to ask an object to delete itself hence your question is somewhat paradox.
This solution later can be generalized so you won't have to write it all over again when you test for the same kind of behavior.
You should insert new object in DB, check that is was inserted, delete it and check that it was deleted. Most obvious way is to use select count(*) to get number of rows.
public class ApplicationTest extends WithApplication {
#Before
public void setup() {
start(fakeApplication(inMemoryDatabase("default-test"), fakeGlobal()));
}
#Test
public void UserModify() {
// create user (User extends Model)
User user = new User();
user.setId(1);
user.setName("name1");
user.save();
int rowCount = Ebean.find(User.class).where().eq("id", 1).findRowCount();
assertEquals(1, rowCount);
user.delete();
rowCount = Ebean.find(User.class).where().eq("id", 1).findRowCount();
assertEquals(0, rowCount);
}
}