Spring Test helpfully rolls back any changes made to the database within a test method. This means that it is not necessary to take the time to delete/reload the test data before each test method.
But if you use the #BeforeClass Junit annotation, then that forces the data loader to be static. A question that is explored here: Why must jUnit's fixtureSetup be static?
If the data initialization method is static, so must the data connection methods and the data source..and on and on...forcing everything to be static...which won't work. At which point, I ask - what good is Spring Test's ability to rollback changes when you have to delete/reload the test data anyway for every test??!?!
One approach that works is to create a "data initialiser" class, add it to a test Spring application context that also has your data source, and wire this application context into your tests. This relies on the fact that Spring caches the application context between test invocations.
For example, a test superclass:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:test-application-context.xml"})
#Transactional
public abstract class DataLoadingTest {
#Autowired
protected DatabaseInitialiser databaseInitialiser;
}
With test-application-context.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" .../>
<bean class="DatabaseInitialiser">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
And
public class DatabaseInitialiser extends JdbcDaoSupport {
#PostConstruct
public void load() {
// Initialise your database here: create schema, use DBUnit to load data, etc.
}
}
In this example:
all tests that rely on the database extend DataLoadingTest;
Spring initialises the application context upon first test invocation;
this calls DatabaseInitialiser.load(), via the #PostConstruct annotation;
Spring keeps the application context in a cache;
further test invocations wire in the DatabaseInitialiser from the application context, which is already cached;
tests are transactional, and roll back at the end to the initial data set.
Likewise, DatabaseInitialiser can have a method annotated #PostDestroy to perform any rollback necessary at the end of the whole test run.
We use DBUnit in conjunction with Spring Test extensively. But we do not use the DBUnit functionality to delete data at the end of the test.
We put a bunch of DBUnit inserts for our test data in the #Before method to initialise the test. Then when the test is complete we let the spring rollback functionality bring the database back to its original state.
The biggest problem we have with this is that the DBUnit data has to be loaded before each test, which can be a major performance hit. Most of our tests using DBUnit are read only, testing the behaviour of the application based on certain predefined behaviour. So we have a habit of creating master tests that then run all the fine grain tests in a batch within the same transaction.
Spring Test and DbUnit is two excellent frameworks. But it doesn't make sense to combine them. Since Spring Test execute a rollback on the connection, it cleans up afterwards, while DbUnit cleans up and insert test data in the #Before method.
Use Spring if you're not dependent on any dynamic data and dbUnit otherwise.
Methods annotated with #BeforeTransaction run, like its name suggests, before the transaction of each test is started. If in such method you can detect if the test data is loaded, then one can load the data when needed.
Beware though that the data is left in your (in-memory) database for all subsequent tests.
We use this to load "static" data that would, in a production environment, also be bootstrapped into our database when starting it. This way we actually use exactly the same code and data for our tests, rather than relying on (DbUnit) exports that might become outdated.
You can create a data initializer "bean", since the config is only run once. It follows the same principle as the main answer, but with less code and classes
#Configuration
class DBUnitTest_Config {
protected String PATH = "";
#Bean
public DataSetConfig setupData(DataSource dataSource) throws SQLException {
DataSetExecutorImpl executor = DataSetExecutorImpl.instance(new ConnectionHolderImpl(dataSource.getConnection()));
DataSetConfig dataSetConfig = new DataSetConfig(PATH);
executor.createDataSet(dataSetConfig);
return dataSetConfig;
}
}
Related
I want to test a service which in turns create connection with redis.
I want to skip this part in my junit. Is there a way to skip this method call or mock it?
I think the question was more about how the Redis part can be mocked so that the test run when redis isn't available. It's hard because your service is probably using the connection so you'd have to do a lot of mocking. What we do in Spring Boot is check if a redis server is available on localhost and if that's the case run the tests, otherwise skip.
See RedisTestServer and a sample usage. Note that the rule applies to all the tests so you may want to move the tests that are using Redis in an isolated test class.
Annotate with #Ignore to ignore the method. Like this:
#Ignore("reason of skipping")
#Test
public void testConnectionCreation(){
// do some stuff...
}
Optionally you can provide a note to why the test is ignored as shown above.
See http://junit.sourceforge.net/javadoc/org/junit/Ignore.html for more info.
I am new to broadleaf application. I am able to run application using tomcat + mysql integration well. Now I want to move on with the development to customize the site project as per my requirement.
I am stuck on the point of persistant in broadleaf site module. I have tried using em.merge that returns my entity but do not save it in database and also tried #Transactional(value="blTransactionManager") but It still problem persists. I have tried bellow code in applicationContext-servlet.xml
<aop:config>
<aop:pointcut id="blMyStoreDao" expression="execution(* com.mycompany.dao.StoreDaoImpl.save*(..))"/>
<aop:advisor advice-ref="blTxAdvice" pointcut-ref="blMyStoreDao"/>
</aop:config>
Here is my controller code
newStore.setCustomer(customer);
newStore.setProductList(new ArrayList<ProductImpl>());
Store getStore=store.save(em, newStore);
System.out.println(getStore.getCustomer().getUsername());
System.out.println("customer fetched: "+customer.getEmailAddress());
Here is my daoimpl code
#Repository("blMyStoreDao")
#Transactional(value="blTransactionManager")
public class StoreDaoImpl implements StoreDao {
#PersistenceContext(unitName="blPU")
protected EntityManager em;
#Transactional(value="blTransactionManager")
public Store save(EntityManager em, Store store) {
System.out.println(em);
System.out.println(store.getCustomer().getUsername());
Store s= em.merge(store);
return s;
}
}
But it also didn't resolve my issue.
Code runs perfectly as it should be, but it doesn't save my entity in database.
Anybody Help. Thanks In advance
There isn't any reason to use <aop:config> especially in applicationContext-servlet.xml (if anywhere it should be in the root application context)
You should use #Transactional(TransactionUtils.DEFAULT_TRANSACTION_MANAGER to annotate your method
It is likely that your class was not being scanned by Spring. In Broadleaf, there is a default component scan set up in applicationContext.xml to scan com.mycompany.core.
I would recommend verifying that your dao is actually scanned by Spring and is initialized as a Spring bean. The fact that the entity manager did not get injected indicates that it did not get loaded by Spring correctly. One way to verify this would be to add an #PostConstruct method and print something or set a breakpoint to verify that it gets hit.
I use Guice to instantiate a VocabularyAPI object for one of my unit tests unitTest1(). However, for another test (unitTest2()), I simply use mockito's #Mock annotation to mock an instance of the same class - VocabularyAPI.
I noticed that when I only run unitTest2() - mockito's mock setting for my VocabularyAPI is configured correctly. However, when I run the entire test suite (both unitTest1() and unitTest2()), both the tests are instantiated with the settings from the injector.
How can I limit the scope of the injected object to only inside the test that it is being injected? I want to be able to use the injected object in unitTest1() and mocked object for unitTest2().
Any problems in using local variables?
In unitTest1():
VocabularyAPI vocabularyAPI = // inject (I'm not familiar with Guice)
In unitTest2():
VocabularyAPI vocabularyAPI = Mockito.mock(VocabularyAPI.class);
i try to use spring-test(3.2.10) and integration tests with TestNG by this link.
I created RootTest.java
#WebAppConfiguration
#ContextConfiguration("file:src/test/resources/root-context2.xml")
public class ReferenceServiceTest extends AbstractTestNGSpringContextTests {
...
spring context loaded success. But my global variables not instantiated because web.xml ignored. In web.xml i have my own "listener-class"(implementation of ServletContextListener) and "context-param". How i can load web.xml context(and calls all application startup listeners) with spring integration test context?
As stated in the reference manual, the Spring MVC Test Framework...
"loads the actual Spring configuration through the TestContext
framework and always uses the DispatcherServlet to process requests
thus approximating full integration tests without requiring a running
Servlet container."
The key point there is "without ... a Servlet container". Thus web.xml does not come into the picture here. In other words, there is no way for configuration in web.xml to have an affect on integration tests using the Spring MVC Test Framework.
Now, having said that, it is possible to register a Servlet Filter with MockMvc like this:
mockMvcBuilder.addFilters(myServletFilter);
or
mockMvcBuilder.addFilters(myResourceFilter, "/resources/*");
And you can configure context-param entries by adding them manually to the ServletContext (which is actually Spring's MockServletContext) before you execute assertions on MockMvc like this:
wac.getServletContext().setInitParameter(name, value);
But... there is no way to configure a ServletContextListener using Spring MVC Test. If you want to have a listener applied to all of your requests that pass through Spring MVC, as an alternative you could consider implementing a custom HandlerInterceptor or WebRequestInterceptor (see Configuring interceptors in the reference manual).
Regards,
Sam
Try with a MockServletContext
#Before
public void before() {
MockServletContext mockServletContext = new MockServletContext();
mockServletContext.setInitParameter("parameterName", "parameterValue");
new MyListenerClass().contextInitialized(new ServletContextEvent(mockServletContext));
}
I have a method which works like this:
public void deploy(UserInput userInput) {
if (userInput is wrong)
return;
//start deployment process
}
The userInput consist of individual checks in the deploy method. Now, I'd like to JUnit test if the user input check algorithms behave right (so if the deployment process would start or not depending on the right or wrong user input). So I need to test this with right and wrong user inputs. I could do this task by checking if anything has been deployed at all, but in this case this is very cumbersome.
So I wonder if it's somehow possible to know in the corresponding JUnit test if the deploy method has been aborted or not (due to wrong user inputs)? (By the way, changing the deploy method is no option.)
As you describe your problem, you can only check your method for side effects, or if it throws an Exception. The easiest way to do this is using a mocking framework like JMockit or Mockito. You have to mock the first method after the checking of user input has finished:
public void deploy(UserInput userInput) {
if (userInput is wrong)
return;
//start deployment process
startDeploy(); // mock this method
}
You can also extend the class under test, and override startDeploy() if it's possible. This would avoid having to use a mocking framework.
Alternative - Integration tests
It sounds like the deploy method is large and complex, and deals with files, file systems, external services (ftp), etc.
It is sometimes easier in the long run to just accept that you're dealing with external systems, and test these external systems. For instance, if deploy() copies a file to directory x, test that the file exists in the target directory. I don't know how complex deploy is, but often mocking these methods can be as hard as just testing the actual behaviour. This may be cumbersome, but like most tests, it would allow you refactor your code so it is simpler to understand. If your goal is refactoring, then in my experience, it's easier to refactor if you're testing actual behaviour rather than mocking.
You could create a UserInput stub / mock with the correct expectations and verify that only the expected calls (and no more) were made.
However, from a design point of view, if you were able to split your validation and the deployment process into separate classes - then your code can be as simple as:
if (_validator.isValid(userInput)) {
_deployer.deploy(userInput);
}
This way you can easily test that if the validator returns false the deployer is never called (using a mocking framework, such as jMock) and that it is called if the validator returns true.
It will also enable you to test your validation and deployment code seperately, avoiding the issue you're currently having.