I have a web services with too many method, before now I "test it" manually with soap, but now I want to do that with Junit and other framework to interact with database and use #EJB annotation.
The first example that I found, was to use DBunit and so I connected to the database and put a row into a table(and it works). But when I try to reuse this connection, and try to directly invoke my #Stateless method I have too many Error such NullPointer exception on the EJB or on the entity manager, so I tried a complet different logic and use Mockito, like this:
public class ReportBeanTest {
//This is my Stateless class
private ReportFc reportBean = new ReportFc();
#Before
public void injectMockEntityManager() throws Exception {
EntityManager entityManager = mock(EntityManager.class);
reportBean.emReport = entityManager;
DateFc dateF= mock(DateFc.class);
reportBean.dateF =dateF;
QuerysFc queryF= mock(QuerysFc .class);
reportBean.queryF =queryF;
reportBean.getReport("myReportA", new Date(), new Date());
}
}
And here my ReportFc.java :
#Stateless
public class ReportFc {
#PersistenceContext(unitName="myDb")
public
EntityManager emReport;
#EJB
public
DateFc dateF;
#EJB
public
QuerysFc queryF;
public List<MyList> getReport(String myReport,
Date from_date,
Date to_date
) throws WSException {
try{
List<WsMap_v3> resultList = new LinkedList<WsMap_v3>();
Date start= dataF.parserDateFormat(from_date,0,"noTime");
Date end= dataF.parserDateFormat(to_date,0,"noTime");
dateF.verifyTimeInterval(start,end);
Query qC=queryF.queryGetReportBetweenDate(start, end, myReportA);
...///
}
I have see that every variable that use external EJB is null, as in my case :
Date start, Date end, Query qC an so on.... What I am doing wrong? there is other way to test this function that use EJB or entitymanager?
I am using maven so if there is other framework to use I have no problem to import it.
Other thing: all my bean of my db are in jar that I import with maven dependecy
Related
I am using a timer to send out emails on a schedule based on a JPA query but I am getting an error that the driver doesn't support XA. I am unable to switch over to an XA driver and whilst I know I can set some options on the data source I am thinking I am not handling transactions correctly.
There is nothing being persisted and the pseudocode of the time would be
Get list of emails to send from DB (from an EntityManager)
Get email addresses (from a CDI bean)
Send emails
So I don't actually need a two phase commit and I was wondering what the correct way of handling this should be?
The code looks like
#Startup
#Singleton
public class EmailTimer {
#PersistenceContext(unitName = "xyz")
private EntityManager em;
#Inject
private EmailLookup emailLookup;
#Resource
TimerService timerService;
#PostConstruct
public void initTimer() {
// define schedule
timerService.createCalendarTimer(schedExpr, timertConfig);
}
#Timeout
private void sendEmails() {
List<Email> emailsToSend = listEmailsToSend();
For (Email e : emailsToSend) {
sendMail(emailLookup.getEmail(e.userName), "Some Text");
}
}
private List<Email> listEmailsToSend() {
String sql = "select ..."; //moderately long select query
TypedQuery<EmailResults> emailResultsQuery = em.createQuery(sql, EmailResults.class);
return emailResultsQuery.getResultList();
}
}
As nothing has been set explicitly everything should be set to TransactionAttributeType.REQUIRED and TransactionManagementType.CONTAINER? so currently everything will be running in the same transaction (hence the need for the two phase commit?
Do I want to mark the #Timeout method as TransactionAttributeType.NOT_SUPPORTED or should I mark the DB method as TransactionAttributeType.REQUIRES_NEW or should I be handling this in a different way?
I am sure that I am missing something, but I don't know exactly what...
Giving the following snippet:
#Service
public class MyClass {
private MyClass self;
private UserRepository userRepository;
private ApplicationContext applicationContext;
#PostConstruct
private void init() {
self = applicationContext.getBean(MyClass.class);
}
#Transactional
public void doA(User user) {
...
if (condition) {
self.doB(user);
throw new SecurityException();
}
user.setRandomField("x");
userRepository.save(user);
}
#Transactional(value = Transactional.TxType.REQUIRES_NEW)
public void doB(User user) {
...
userRepository.save(user);
}
}
What do I know about #Transactional is that if it is used, is redundant to call repository.save(entity).
What I am trying to do, is to process an entity from a transactional method, and if there is a breaking condition, call a new method (annotated with REQUIRES_NEW) that will update some fields of the entity and save it. The root method (doA) then throws an exception. FYI: the #Transactional(dontRollbackOn = SecurityException.class) is not an option in this situation.
For using this commiting mechanism, instead of creating a new bean just with one method I just injected the current bean into a variable just called self, therefore I can use the bean proxy for transaction management.
The odd thing is that if I am removing from doB the save call, when doA transaction is rollbacked because of the SecurityException, the changes performed by doB are rollbacked as well. But if I let it in there, this is working as expected.
Am I doing something wrong or am I missing something?
Thanks!
Try to do not pass User instance in the doB().
Pass an Id instead and read the User from the repo internally. I am not sure how the attached entity is handled between the different sessions.
I am trying to test the mechanism of rollbackin transaction in cases of somthing went wrong. I read many similar topics, but nothing helps me. Here is what i try:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/rest-servlet.xml" })
#Transactional
public class TagDaoImplTest extends DatabaseTestCase {
private static final String FLAT_XML_DATASET = "FlatXmlDataSet.xml";
#Autowired
private TagDao tagDao;
#Autowired
private SessionFactory sessionFactory;
#Before
public void setUp() throws Exception {
DatabaseOperation.REFRESH.execute(getConnection(), getDataSet());
}
#Test
public void testAddWithRollback() throws Exception {
addWithRollback("testTagToAdd"); //i suppouse that we tried to add, but somthing went wrong and transaction was rolled back
final Tag testTagToAdd = tagDao.findByTag("testTagToAdd"); // so db must be without changes and i check this
assertNull(testTagToAdd);
}
#Rollback(true) //i want this method to rollback after its work to imitate corrupted transaction
private void addWithRollback(String tag) throws Exception {
tagDao.add(new Tag(tag));
}
}
My dao looks like this:
#Repository("tagDao")
public class TagDaoImpl implements TagDao {
#Override
public void add(Tag tag) {
final Session session = sessionFactory.getCurrentSession();
session.persist(tag);
}
}
But my test fails because it finds that tag in db (and this means transaction wasn`t rolled back). I tried many different things like get current session and transaction and manually invoke rollback, but nothing happend. Can you please help me?
First of all, for me it feels a bit weird that you try to test the repository layer. Normally there should not be any business logic, thus this means that you try to test Hibernate or SQL which are already tested million of times and there is no point of doing it.
I would suggest to annotate your method with something like this:
#Transactional(rollbackFor=Exception.class)
and maybe specify the Exception. Then in the test you prepare your system in a way that this method throws this exception. Thus it should be rolled back and no data should be changed.
Furthermore, I would like to add that actually loading spring context at this point most probably is different compare to the production one. Thus this is an additional point where I would say that there is no point of doing it. At least on the repository layer.
I have a Question regarding the JPA Usage in Play.
I have already created a Model Class and annotated it with #Entity, and a Controller Class, in which i have a static method annotated with #play.db.jpa.Transactional. When i start activator run, everything is compiled correctly, and the Database is started, but as soon as the Code where i call the Entity Manager via
EntityManager em = play.db.jpa.JPA.em();
a NullException is thrown.
As far as I am concerned, the persistence.xml and the application.conf is correct, i have already researched the web, but to no avail.
What are possible Solutions for this?
Thanks in advance!
Here is the concrete Piece of code where I use the JPA:
public class UserController extends Controller {
#play.db.jpa.Transactional
public static Result registerResponse(){
System.out.println("registerResponse called!");
Form<MyUser> regForm = Form.form(MyUser.class).bindFromRequest();
if (regForm.hasErrors()) {
System.out.println("bad request");
System.out.println("Form: " + regForm.toString());
System.out.println("Errors: "+regForm.errors().toString());
return badRequest(views.html.registration.render(regForm,Arrays.asList(Avatar.values())));
} else {
MyUser newuser = regForm.get();
System.out.println("persisting");
EntityManager em = play.db.jpa.JPA.em(); //Here is the Nullpointer exception
em.persist(newuser);
System.out.println("persisted");
return ok(authentication.render(Form.form(Login.class)));
}
}
I think that you do not need to instatiate this class, you need to use he methods in play.db.jpa.JPA.em()
change this
EntityManager em = play.db.jpa.JPA.em(); //Here is the Nullpointer exception
em.persist(newuser);
by this:
try {
JPA.em().persist(newuser);
}
catch(PersistenceException pe){
//the code for the exception
}
with the import import play.db.jpa.JPA;
In my unit tests I autowired some DataSources, which use URLs like
jdbc:derby:memory:mydb;create=true
to create an in-memory DBs.
To drop an in-memory Derby db you have to connect with:
jdbc:derby:memory:mydb;drop=true
I would like this to happen after every test and start with a fresh db. How can I do this using Spring?
How to shutdown Derby in-memory database Properly
gave me a hint to a solution:
mydb.drop.url = jdbc:derby:memory:mydb;drop=true
...
<bean id="mydbDropUrl" class="java.lang.String">
<constructor-arg value="${mydb.drop.url}" />
</bean>
...
#Resource
private String mydbDropUrl;
#After
public void tearDown() {
try {
DriverManager.getConnection(mydbDropUrl);
} catch (SQLException e) {
// ignore
}
}
A downside is the use of the String constructor which accepts a String (an immutable String object around an immutable String object). I read that there is a #Value annotation in Spring 3, which might help here, but I'm using Spring 2.5.
Please let me know if you have a nicer solution.
There is a database-agnostic way to do this if you are using Spring together with Hibernate.
Make sure the application context will be created / destroyed before / after every test method:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"classpath*:application-context-test.xml"})
#TestExecutionListeners({DirtiesContextTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class})
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public abstract class AbstractTest {
}
Instruct Hibernate to auto create the schema on startup and to drop the schema on shutdown:
hibernate.hbm2ddl.auto = create-drop
Now before every test
the application context is created and the required spring beans are injected (spring)
the database structures are created (hibernate)
the import.sql is executed if present (hibernate)
and after every test
the application context is destroyed (spring)
the database schema is dropped (hibernate).
If you are using transactions, you may want to add the TransactionalTestExecutionListener.
After spring test 3, you can use annotations to inject configurations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/spring-test.xml")
public class MyTest {
}
Just do something like:
public class DatabaseTest implements ApplicationContextAware {
private ApplicationContext context;
private DataSource source;
public void setApplicationContext(ApplicationContext applicationContext) {
this.context = applicationContext;
}
#Before
public void before() {
source = (DataSource) dataSource.getBean("dataSource", DataSource.class);
}
#After
public void after() {
source = null;
}
}
Make your bean have a scope of prototype (scope="prototype"). This will get a new instance of the data source before every test.
If you use the spring-test.jar library, you can do something like this:
public class MyDataSourceSpringTest extends
AbstractTransactionalDataSourceSpringContextTests {
#Override
protected String[] getConfigLocations() {
return new String[]{"classpath:test-context.xml"};
}
#Override
protected void onSetUpInTransaction() throws Exception {
super.deleteFromTables(new String[]{"myTable"});
super.executeSqlScript("file:db/load_data.sql", true);
}
}
And an updated version based on latest comment, that drops db and recreates tables before every test:
public class MyDataSourceSpringTest extends
AbstractTransactionalDataSourceSpringContextTests {
#Override
protected String[] getConfigLocations() {
return new String[]{"classpath:test-context.xml"};
}
#Override
protected void onSetUpInTransaction() throws Exception {
super.executeSqlScript("file:db/recreate_tables.sql", true);
}
}
This is what we do at the start of every test.
Drop all Previous Objects.
Create all tables mentioned in the create_table.sql
Insert values onto the created tables based on what you want to test.
#Before
public void initialInMemoryDatabase() throws IOException, FileNotFoundException {
inMemoryDerbyDatabase.dropAllObjects();
inMemoryDerbyDatabase.executeSqlFile("/create_table_policy_version_manager.sql");
inMemoryDerbyDatabase.executeSqlFile("/insert_table_policy_version_manager.sql");
}
Works like a charm!