Spring / DbUnit closes connection after one test - spring

So, we need to write integration tests for our Java-configurated Spring Application (3.2.3) with an Oracle data base. There's a separate schema which gets populated by Spring-test-DbUnit and the first test runs without any problems. All the other following tests, no matter if they're in the same class or not, fail due to a closed connection:
java.sql.SQLRecoverableException: closed connection
at oracle.jdbc.driver.PhysicalConnection.createStatement(PhysicalConnection.java:3423)
at oracle.jdbc.driver.PhysicalConnection.createStatement(PhysicalConnection.java:3398)
at org.dbunit.database.statement.AbstractBatchStatement.<init>(AbstractBatchStatement.java:50)
at org.dbunit.database.statement.SimpleStatement.<init>(SimpleStatement.java:49)
at org.dbunit.database.statement.PreparedStatementFactory.createBatchStatement(PreparedStatementFactory.java:57)
at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:85)
at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
at com.github.springtestdbunit.DbUnitRunner.setupOrTeardown(DbUnitRunner.java:194)
at com.github.springtestdbunit.DbUnitRunner.beforeTestMethod(DbUnitRunner.java:66)
at com.github.springtestdbunit.DbUnitTestExecutionListener.beforeTestMethod(DbUnitTestExecutionListener.java:186)
at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:348)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
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:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
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:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Here's our data source:
#Override
#Bean
public DataSource dataSource()
{
String conString = "jdbc:oracle:thin:#localhost:1521:XE";
String username = "john";
String password = "doe";
Driver driver = new OracleDriver();
SimpleDriverDataSource dataSource = new SimpleDriverDataSource(driver, conString, username, password);
return dataSource;
}
And this is a sample integration test class:
#ContextConfiguration(classes = { IntegrationTestConfiguration.class })
#ActiveProfiles(Constants.PROFILE_INTEGRATION)
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class, DbUnitTestExecutionListener.class, ForeignKeyDisabler.class })
#DbUnitConfiguration(databaseConnection = "oracleConnection")
#DatabaseSetup("/database/snapshot/snapshot1.xml")
public class IntegrationTest extends AbstractTransactionalJUnit4SpringContextTests
{
#Autowired
private NewsService newsService;
#Test
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void testSpringConfiguration()
{
this.assertNewsSize(1);
News news1 = new News();
news1.setTitle("Test News 1");
News savedNews1 = this.newsService.save(news1);
Assert.assertTrue(savedNews1.getId() > 0);
News news2 = new News();
news2.setTitle("Test News 2");
News savedNews2 = this.newsService.save(news2);
Assert.assertTrue(savedNews2.getId() > 0);
News news3 = new News();
news3.setTitle("Test News 3");
News savedNews3 = this.newsService.save(news3);
Assert.assertTrue(savedNews3.getId() > 0);
this.assertNewsSize(4);
}
#Test
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void testSpringConfigurationAgain()
{
this.assertNewsSize(1);
News news1 = new News();
news1.setTitle("Test News 1");
News savedNews1 = this.newsService.save(news1);
Assert.assertTrue(savedNews1.getId() > 0);
News news2 = new News();
news2.setTitle("Test News 2");
News savedNews2 = this.newsService.save(news2);
Assert.assertTrue(savedNews2.getId() > 0);
News news3 = new News();
news3.setTitle("Test News 3");
News savedNews3 = this.newsService.save(news3);
Assert.assertTrue(savedNews3.getId() > 0);
this.assertNewsSize(4);
}
private void assertNewsSize(int newsSize)
{
List<News> allNews = this.newsService.getNews();
Assert.assertEquals(newsSize, allNews.size());
}
}
Might this be problem of the Spring's database connection behavior to close a connection after committing/rolling back a transaction? If yes, how can I solve this? My last try was to create transaction on class/method base but without success.
Thank you in advance.

I believe its connected to your DirtiesContextTestExecutionListener.class which is some kind of equivalent of
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/annotation/DirtiesContext.html .
Test annotation which indicates that the ApplicationContext associated with a test is dirty and should be closed:
...
after each test method in the current test class, when declared at the
class level with class mode set to AFTER_EACH_TEST_METHOD
so probably spring is closing your beans after 1st test method. Maybe its easier to just clean up database in #AfterMethod method? It would run after each test.

Thanks to freakman, we've got a solution that seems to work for us:
We created our own classes
OurOwnDbUnitTestExecutionListener.java
OurOwnDbUnitRunner.java
based on Spring-test-DbUnit's
com.github.springtestdbunit.DbUnitTestExecutionListener.java
com.github.springtestdbunit.DbUnitRunner.java
classes. Note that the package name for our classes must be equal due to the use of package-scoped classes. Since the listener uses the runner in a non-configurable manner, we use our own DbUnit runner:
private static OurOwnDbUnitRunner runner = new OurOwnDbUnitRunner();
The runner is modified so it does not close the connections after completing a test method. Line 116 is removed:
// testContext.getConnections().closeAll();
Finally, we use our modified DbUnitTestExecutionListener in our test class:
#TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
OurOwnDbUnitTestExecutionListener.class, // <<< this does the trick
ForeignKeyDisabler.class })

If you're using spring-test-dbunit, another solution might be to provide a dbUnitDatabaseconnection that overwrites the close-method:
#Bean
public IDatabaseConnection dbUnitDatabaseConnection(DataSource dataSource) throws SQLException, DatabaseUnitException {
return new CustomDatabaseConnection(dataSource.getConnection());
}
private static class CustomDatabaseConnection extends DatabaseConnection {
public CustomDatabaseConnection(Connection connection) throws DatabaseUnitException {
super(connection);
}
#Override
public void close() {
// don't close the connection
}
}

Related

Spring AOP NullPointerException after running successfully for an extended period of time

This is a problem which has stumped myself and two of my colleagues for a few days now.
We are receiving a NullPointerException after our spring-boot microservice has been running without a hitch anywhere from a few minutes to a few hours and has received a few hundred to few thousand requests. This issue started after a few beans were changed to being request-scoped due to a requirements change.
Classes (all objects are autowired/constructed at microservice boot):
// New class introduced to accommodate requirements change.
#Repository("databaseUserAccountRepo")
public class DatabaseAccountUserRepoImpl implements UserLdapRepo {
private final DatabaseAccountUserRepository databaseAccountUserRepository;
#Autowired
public DatabaseAccountUserRepoImpl(
#Qualifier("databaseAccountUserRepositoryPerRequest") final DatabaseAccountUserRepository databaseAccountUserRepository
) {
this.databaseAccountUserRepository = databaseAccountUserRepository;
}
// ...snip...
}
// ==============================================================================
// New class introduced to accommodate requirements change.
#Repository("databaseAccountUserRepository")
public interface DatabaseAccountUserRepository
extends org.springframework.data.repository.CrudRepository {
// ...snip...
}
// ==============================================================================
#Repository("ldapUserAccountRepo")
public class UserLdapRepoImpl implements UserLdapRepo {
// ...snip...
}
// ==============================================================================
#Component
public class LdapUtils {
private final UserLdapRepo userLdapRepo;
#Autowired
public LdapUtils(
#Qualifier("userLdapRepoPerRequest") final UserLdapRepo userLdapRepo
) {
this.userLdapRepo = userLdapRepo;
}
// ...snip...
public Object myMethod(/* whatever */) {
// ...snip...
return userLdapRepo.someMethod(/* whatever */);
}
}
// ==============================================================================
// I have no idea why the original developer decided to do it this way.
// It's worked fine up until now so I see no reason to change it unless
// I really need to.
public class AuthenticationContext {
private static final ThreadLocal<String> organizationNameThreadLocal = new ThreadLocal<>();
// ...snip...
public static void setOrganizationName(String organizationName) {
organizationNameThreadLocal.set(organizationName);
}
public static String getOrganizationName() {
return organizationNameThreadLocal.get();
}
public static void clear() {
organizationNameThreadLocal.remove();
}
// ...snip...
}
// ==============================================================================
public class AuthenticationContextInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
AuthenticationContext.setOrganizationName(request.getHeader("customer-id"));
return true;
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
AuthenticationContext.clear();
}
}
Code to request-scope:
#Configuration
// We have some aspects in our codebase, so this might be relevant.
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class ServiceConfiguration {
// ...snip...
#Bean
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public UserLdapRepo userLdapRepoPerRequest(
final Map<String, String> customerIdToUserLdapRepoBeanName
) {
final String customerId = AuthenticationContext.getOrganizationName();
final String beanName = customerIdToUserLdapRepoBeanName.containsKey(customerId)
? customerIdToUserLdapRepoBeanName.get(customerId)
: customerIdToUserLdapRepoBeanName.get(null); // default
return (UserLdapRepo) applicationContext.getBean(beanName);
}
#Bean
public Map<String, String> customerIdToUserLdapRepoBeanName(
#Value("${customers.user-accounts.datastore.use-database}") final String[] customersUsingDatabaseForAccounts
) {
final Map<String, String> customerIdToUserLdapRepoBeanName = new HashMap<>();
customerIdToUserLdapRepoBeanName.put(null, "ldapUserAccountRepo"); // default option
if (customersUsingDatabaseForAccounts != null && customersUsingDatabaseForAccounts.length > 0) {
Arrays.stream(customersUsingDatabaseForAccounts)
.forEach(customerId ->
customerIdToUserLdapRepoBeanName.put(customerId, "databaseUserAccountRepo")
);
}
return customerIdToUserLdapRepoBeanName;
}
// Given a customer ID (taken from request header), returns the
// DatabaseAccountUserRepository instance for that particular customer.
// The DatabaseAccountUserRepositoryProvider is NOT request-scoped.
// The DatabaseAccountUserRepositoryProvider is basically just a utility
// wrapper around a map of String -> DatabaseAccountUserRepository.
#Bean
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public DatabaseAccountUserRepository databaseAccountUserRepositoryPerRequest(
final DatabaseAccountUserRepositoryProvider databaseAccountUserRepositoryProvider
) {
final String customerId = AuthenticationContext.getOrganizationName();
return databaseAccountUserRepositoryProvider.getRepositoryFor(customerId);
}
// ...snip...
}
The stack trace:
java.lang.NullPointerException: null
at org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry.getInterceptors(DefaultAdvisorAdapterRegistry.java:81)
at org.springframework.aop.framework.DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(DefaultAdvisorChainFactory.java:89)
at org.springframework.aop.framework.AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport.java:489)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:659)
at com.mycompany.project.persistence.useraccount.ldap.UserLdapRepoImpl$$EnhancerBySpringCGLIB$$b6378f51.someMethod(<generated>)
at sun.reflect.GeneratedMethodAccessor304.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy209.findByFederatedInfo(Unknown Source)
at com.mycompany.project.util.LdapUtils.myMethod(LdapUtils.java:141)
The method in which the NPE is thrown is this guy:
//////////////////////////////////////////
// This is a method in Spring framework //
//////////////////////////////////////////
#Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice(); // <<<<<<<<<< line 81
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
Most relevant dependencies:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!-- this results in spring-aop:4.3.14.RELEASE -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
The request header customer-id is set by our proxy, so it must be available on the request (we added logging to verify that this statement is true; it is).
We do not know the exact traffic pattern which can cause the NPE to start being triggered. Once triggered, all subsequent requests also result in an NPE.
We have several other request-scoped beans in this project; they are also selected using the customer-id. Several of said objects have existed in this project for months prior to this change. They do not exhibit this problem.
We believe that the userLdapRepoPerRequest() and databaseAccountUserRepositoryPerRequest() methods are working correctly - receiving the correct customer-id, is returning the correct object, etc...at least when the methods are hit. This was determined by adding logging to the body of those methods - a log message immediately upon entering the method which records the parameter, one log message verifying value of the customer-id, and one log message immediately before returning which records the value which is to be returned. Note: Our logging setup has a correlation ID present on each message, so we can keep track of what messages corresponds the same request.
It's almost as if Spring is losing track of a few of its proxied beans.
Anyone have any ideas on what's happening or anything you would like us to try? Any leads are much appreciated.

Spring's #DirtiesContext leads to Hibernate exception

I have a JUnit integration test which tests the stability of an Apache CXF webservice. The test inherits the webserviceTestclient which does a real webservice call to an endpoint. To simulate an error in the application, I mock an endpoint dependency to provoke an exception.
The challenge here is: How to reset the endpoint's dependency or how to recreate Spring's application context so that subsequent tests will run their tests properly with a clean context and unmocked beans. My best approach so far:
Versions used: Spring 3.2.3, Hibernate 4.2.5, Mockito 1.9.5
Method to test:
#Override
public boolean foo() throws FooException
{
try
{
return this.someService.foo();
}
catch (Exception exception)
{
throw this.convertToFooException(exception);
}
}
JUnit test:
public class IntegrationTest extends WebserviceTestbase
{
#InjectMocks
private ClassToTest classToTest;
#Mock
private SomeService someServiceMock;
#Test
#DirtiesContext
public void thisTestFails()
{
// given
when(this.someServiceMock.foo().thenThrow(new RuntimeException());
try
{
// when
this.webserviceTestclient.foo();
fail();
}
catch (FooException FooException)
{
// then test passed
}
}
}
When I execute the test above the test fails and I get the following stacktrace:
org.springframework.transaction.TransactionSystemException: Could not roll back JPA transaction; nested exception is javax.persistence.PersistenceException: unexpected error when rollbacking
at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:543)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:846)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:823)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:588)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:297)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:192)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:395)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:91)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
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:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
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:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: javax.persistence.PersistenceException: unexpected error when rollbacking
at org.hibernate.ejb.TransactionImpl.rollback(TransactionImpl.java:109)
at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:539)
... 25 more
Caused by: org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.stat.spi.StatisticsImplementor]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:126)
at org.hibernate.internal.SessionFactoryImpl.getStatisticsImplementor(SessionFactoryImpl.java:1480)
at org.hibernate.internal.SessionFactoryImpl.getStatistics(SessionFactoryImpl.java:1476)
at org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl.afterTransaction(TransactionCoordinatorImpl.java:140)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.afterTransactionCompletion(JdbcTransaction.java:138)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.rollback(AbstractTransactionImpl.java:214)
at org.hibernate.ejb.TransactionImpl.rollback(TransactionImpl.java:106)
... 26 more
Hope that anyone can help.
Best regards!
As a works-for-me-in-a-dirty-way-solution, I now changed the dependency via reflection:
#Autowired
private ClassToTest classToTest;
private SomeService someServiceBean;
#Override
#Before
public void setup()
{
super.setup();
// remember the currect dependency and replace it with null to provoke a RuntimeException
this.someServiceBean = (SomeService ) ReflectionTools.getFieldValue(this.classToTest, "someService");
ReflectionTools.setFieldValue(this.classToTest, "someService", null);
}
#Test
public void thisTestNowPasses()
{
// given
try
{
// when
this.webserviceTestclient.foo();
fail();
}
catch (FooException FooException)
{
// then test passed
}
}
#Override
#After
public void cleanup()
{
super.cleanup();
// restore the dependency so other tests won't fail
ReflectionTools.setFieldValue(this.classToTest, "someService", this.someServiceBean);
}
Here are the ReflectionTools:
public class ReflectionTools
{
public static Object getFieldValue(Object instanceToInspect, String fieldName)
{
Object fieldValue = null;
try
{
Field declaredFieldToGet = instanceToInspect.getClass().getDeclaredField(fieldName);
declaredFieldToGet.setAccessible(true);
fieldValue = declaredFieldToGet.get(instanceToInspect);
declaredFieldToGet.setAccessible(false);
}
catch (Exception exception)
{
String className = exception.getClass().getCanonicalName();
String message = exception.getMessage();
String errorFormat = "\n\t'%s' caught when getting value of field '%s': %s";
String error = String.format(errorFormat, className, fieldName, message);
Assert.fail(error);
}
return fieldValue;
}
public static void setFieldValue(Object instanceToModify, String fieldName, Object valueToSet)
{
try
{
Field declaredFieldToSet = instanceToModify.getClass().getDeclaredField(fieldName);
declaredFieldToSet.setAccessible(true);
declaredFieldToSet.set(instanceToModify, valueToSet);
declaredFieldToSet.setAccessible(false);
}
catch (Exception exception)
{
String className = exception.getClass().getCanonicalName();
String message = exception.getMessage();
String errorFormat = "\n\t'%s' caught when setting value of field '%s': %s";
String error = String.format(errorFormat, className, fieldName, message);
Assert.fail(error);
}
}
}
Hope that this helps someone.

Testing that delete is correctly rolled back with DataIntegrityViolationException junit, spring, #Transactional

I have a category -> subCategory -> products hierarchy in my application. If a subcategory has no products, you are allowed to delete it. If a subCategory has products, the DAO throws a DataIntegrityViolationException and the transaction should be rolled back.
In my tests, I have:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {TestTransactionManagement.class})
public class BusinessSubCategoryCRUDTest {
#Autowired
public void setCRUD(BusinessSubCategoryCRUD crud) {
this.crud = crud;
}
// #Transactional
#Test
public void testDeleteBusinessSubCategoryInUseCanNotBeDeleted() {
final long id = 1;
BusinessSubCategory subCategoryBeforeDelete =
crud.readBusinessSubCategory(id);
final int numCategoriesBeforeDelete =
subCategoryBeforeDelete.getBusinessCategories().size();
try {
crud.deleteBusinessSubCategory(
new BusinessSubCategory(id, ""));
} catch (DataIntegrityViolationException e) {
System.err.println(e);
}
BusinessSubCategory subCategoryAfterDeleteFails =
crud.readBusinessSubCategory(id);
// THIS next assertion is the source of my angst.
// At this point the the links to the categories will have been
// been deleted, an exception will have been thrown but the
// Transaction is not yet rolled back if the test case (or test
// class) is marked with #Transactional
assertEquals(
numCategoriesBeforeDelete,
subCategoryAfterDeleteFails.getBusinessCategories().size());
}
}
However, if I uncomment the #Transactional above #Test, it fails. I think the DAO is using the transaction from the #Test and so the transaction doesn't roll back until AFTER I check to be sure the transaction has been rolled back.
#Transactional(readOnly = false, propagation =
Propagation.REQUIRED)
public boolean deleteBusinessSubCategory(
BusinessSubCategory businessSubCategory) {
BeanPropertySqlParameterSource paramMap = new
BeanPropertySqlParameterSource(businessSubCategory);
namedJdbcTemplate.update(
DELETE_CATEGORY_SUB_CATEGORY_BY_ID_SQL,
paramMap);
return 0 != namedJdbcTemplate.update(
DELETE_SUB_CATEGORY_BY_ID_SQL,
paramMap);
}
So, how do I have the DAO code still inherit the transaction from the context it is running in (in production it inherits the transaction from the service it is running in) but still be able to test it. I want to put #Transactional on the entire test class, but that then leaves my test either failing or incomplete.
For completeness, here is my configuration class for the test.
#Configuration
#EnableTransactionManagement
public class TestTransactionManagement {
#Bean
public EmbeddedDatabase getDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.HSQL) //.H2 or .DERBY
.addScript("sql/create-db.sql")
.addScript("sql/create-test-data.sql")
.build();
return db;
}
#Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(getDataSource());
}
#Bean
public BusinessSubCategoryCRUD getCRUD() {
return new BusinessSubCategoryCRUD(getDataSource());
}
}
The "solution" or workaround was to reset the database before each test. Then there was no need for an #Transactional on the test, the rollback could be tested, and the test suite ran slighly slower due to the additional database setup.
#Before
public void setUp() {
Connection conn = DataSourceUtils.getConnection(dataSource);
ScriptUtils.executeSqlScript(
conn, new ClassPathResource("sql/create-test-data.sql"));
DataSourceUtils.releaseConnection(conn, dataSource);
}

Any samples to unit test fallback using Hystrix Spring Cloud

I wish to test the following scenarios:
Set the hystrix.command.default.execution.isolation.thread.timeoutInMillisecond value to a low value, and see how my application behaves.
Check my fallback method is called using Unit test.
Please can someone provide me with link to samples.
A real usage can be found bellow. The key to enable Hystrix in the test class are these two annotations:
#EnableCircuitBreaker
#EnableAspectJAutoProxy
class ClipboardService {
#HystrixCommand(fallbackMethod = "getNextClipboardFallback")
public Task getNextClipboard(int numberOfTasks) {
doYourExternalSystemCallHere....
}
public Task getNextClipboardFallback(int numberOfTasks) {
return null;
}
}
#RunWith(SpringRunner.class)
#EnableCircuitBreaker
#EnableAspectJAutoProxy
#TestPropertySource("classpath:test.properties")
#ContextConfiguration(classes = {ClipboardService.class})
public class ClipboardServiceIT {
private MockRestServiceServer mockServer;
#Autowired
private ClipboardService clipboardService;
#Before
public void setUp() {
this.mockServer = MockRestServiceServer.createServer(restTemplate);
}
#Test
public void testGetNextClipboardWithBadRequest() {
mockServer.expect(ExpectedCount.once(), requestTo("https://getDocument.com?task=1")).andExpect(method(HttpMethod.GET))
.andRespond(MockRestResponseCreators.withStatus(HttpStatus.BAD_REQUEST));
Task nextClipboard = clipboardService.getNextClipboard(1);
assertNull(nextClipboard); // this should be answered by your fallBack method
}
}
Fore open the circuit in your unit test case just before you call the client. Make sure fall back is called. You can have a constant returned from fallback or add some log statements.
Reset the circuit.
#Test
public void testSendOrder_openCircuit() {
String order = null;
ServiceResponse response = null;
order = loadFile("/order.json");
// use this in case of feign hystrix
ConfigurationManager.getConfigInstance()
.setProperty("hystrix.command.default.circuitBreaker.forceOpen", "true");
// use this in case of just hystrix
System.setProperty("hystrix.command.default.circuitBreaker.forceOpen", "true");
response = client.sendOrder(order);
assertThat(response.getResultStatus()).isEqualTo("Fallback");
// DONT forget to reset
ConfigurationManager.getConfigInstance()
.setProperty("hystrix.command.default.circuitBreaker.forceOpen", "false");
// use this in case of just hystrix
System.setProperty("hystrix.command.default.circuitBreaker.forceOpen", "false");
}

SpringMVC- Mockito- Junit - NullPointerException when service class method is called from controller class

I am writing a web-application, by using spring MVC . I have made a service class to map things to and from the database using UI.
My problem is I am new to junit and mockito
when i am trying to write unit tests on Controller class, it always returns a NullPointerException. It is really annoying since I am unable to find the answer, so I hope you guys can help me out. Below I have posted my code.
My Controller class method on /update return success
#RequestMapping(value = "/update", method = RequestMethod.POST)
public String updateFormData(#ModelAttribute CRDetails certGuide,
ModelMap model) {
crService.updateCertification(certGuide);
return "success";
}
My Service class method updates mongodb with modified data
public void updateCertification(CRDetails certGuide) { String userTypeSubmitted = certGuide.getCertGuidelines().getUserType(); System.out.println("updated by " + userTypeSubmitted); Update update = new Update(); Query query = new Query(Criteria.where("cr").is("CR1"));
CRDetails details = certMongoTemplate.findOne(query, CRDetails.class,
COLLECTION_NAME); CertificateGuidelines newCertGuide = new CertificateGuidelines();
if (details != null) { newCertGuide.setCertG(certGuide.getCertGuidelines().getCertG()); if (userTypeSubmitted.equals("Certification Team")
&& userTypeSubmitted != "") {
newCertGuide.setStatus("Pending with Document Developer"); } else {
newCertGuide.setStatus("Pending with Certification Team"); } newCertGuide.setHistoryCount(++count);
// converting it into mongo document. MongoConverter converter = certMongoTemplate.getConverter(); DBObject newRec = (DBObject) converter
.convertToMongoType(newCertGuide); update.set("certGuidelines", newRec); }
System.out.println("new cert guide " + newCertGuide.getCertG() + " "
+ newCertGuide.getStatus() + " "
+ newCertGuide.getHistoryCount() + " "
+ newCertGuide.getUserType());
certMongoTemplate.updateFirst(query, update, CRDetails.class); }
My controllerTest class which return NullPointerException.
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.test.web.server.MockMvc;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.View;
import com.cerner.docworks.controller.CRController;
import com.cerner.docworks.domain.CRDetails;
import com.cerner.docworks.service.CRService;
public class CRControllerTest {
/*#Mock private CRService service;*/
#Mock View mockView;
#InjectMocks
private CRController crController;
private MockMvc mockMvc;
#Before public void setup() {
}
#Test public void testUpdate() throws Exception { // CRService service = Mockito.mock(CRService.class); CRService crService = Mockito.spy(new CRService()); ModelMap model = Mockito.mock(ModelMap.class); CRDetails certGuide = Mockito.spy(new CRDetails());
CRController controller = new CRController();
// Mockito.when(service.updateCertification(certGuide)); // Mockito.when(model.addAttribute(Matchers.eq("certGuide"),any(String.class))).thenReturn(null); // Mockito.doThrow(new RuntimeException()).when(crService).updateCertification(certGuide); Mockito.doNothing().when(crService).updateCertification(certGuide); Mockito.mockingDetails(certGuide); // Mockito.doCallRealMethod().when(crService).updateCertification(certGuide); // Mockito.(crService)).updateCertification(certGuide);; String fileName = controller.updateFormData(certGuide, model);
System.out.println(fileName); // Mockito.verify(controller).updateFormData(certGuide, model); assertEquals("success", fileName); } }
Trace:
java.lang.NullPointerException at
com.cerner.docworks.controller.CRController.updateFormData(CRController.java:81)
at
com.cerner.docworks.controller.test.CRControllerTest.testUpdate(CRControllerTest.java:62)
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:483) 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.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
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.junit.runners.ParentRunner.run(ParentRunner.java:363) at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
FYI,
CRDetails is a pojo class with
private String id;
private String cr;
private String desc;
private CertificateGuidelines certGuidelines;
private Date dueDate;
//private String userType;
private String solutionName;
FYI,
When i am debugging the code, i found mock is setting objects to null
If i do set details manually, test case pass but, i want to use mockito.
Thanks in advance for ur help.
You need to run the test with the MockitoJUnitRunner, e.g.:
#RunWith(MockitoJUnitRunner.class)
public class CRControllerTest {
// ...
This allows #InjectMocks and #Mock to work properly. I.e. mockView will be created as a mock of View and crController will be created with relevant #Mock-annotated fields.
You can refer to the documentation to see how the mocks are injected.

Resources