How to Retrieve and Modify the #ConfigurationContext programmatically via code ?
I have a default configuration where it contains valid xml files.
Now i need to add an invalid configuration for a particular test case and test the same.
How to override, retrieve and modify the #ConfigurationContext programmatically via code ?
Thanks in advance,
Kathir
Disclaimer: I am assuming you are using JUnit since you didn't comment differently in your reply to my comment.
I think what you are trying to do does not make lot of sense, in my opinion it is still better to create a dedicated test class for your not-working configuration in order to be able to do more than one test. However:
annotate your test class with #RunWith(SpringJUnit4ClassRunner.class) and #ContextConfiguration(locations = {"classpath:/working-context.xml"}). In this way you can retrieve the configuration context in two ways: first, you can simply declare a field #Inject ApplicationContext context which will contain the working context. Or, you make your test class implements ApplicationContextAware and then write a public void setApplicationContext (ApplicationContext applicationContext). I would go for the second one since it will come in hand for changing the context programmatically.
write a not-working-context.xml and place it in your classpath
in the test method you want to fail, reload the application context with context = setApplicationContext(new ClassPathXmlApplicationContext("not-working-context.xml")); and test all the errors you like.
though it is not good practice to stand on test case order, make sure your failing test will be executed as the last one (tests are executing alphabetically) so you don't have to reload the working context in the other tests.
In the end your test class will look like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/working-context.xml"})
public class TestClass implements ApplicationContextAware {
private ApplicationContext context;
public void setApplicationContext(ApplicationContext context){
this.context = context;
}
//Other tests
#Test
public void zFailingTest() {
context = setApplicationContext(new ClassPathXmlApplicationContext("not-working-context.xml"));
//your test
}
}
Related
we have selenium tests which are ran by java test class.
On local environment everything is ok, but I want to switch off those tests when run on jenkins.
So I use:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebIntegrationTest("server.port=1234")
#Profile("!jenkins")
#ActiveProfiles("integrationtests")
public class LoginAndEditProfileSeleniumTest {
...
What works:
running mvn clean test run all tests locally, with integrationtests profile active. I dont want to pass any additional parameter.
What I want to achieve:
running mvn clean test -Dspring.profiles.active=jenkins switch off this test.
Can I merge somehow profile passed by parameter, ActiveProfile annotation and take Profile annotation into consideration? :)
//update:
Its possible to use class extending ActiveProfilesResolver:
public class ActiveProfileResolver implements ActiveProfilesResolver {
#Override
public String[] resolve(Class<?> testClass) {
final String profileFromConsole = System.getProperty("spring.profiles.active");
List<String> activeProfiles = new ArrayList<>();
activeProfiles.add("integrationtests");
if("jenkins".contains(profileFromConsole)){
activeProfiles.add("jenkins");
}
return activeProfiles.toArray(new String[activeProfiles.size()]);
}
}
but it seems to not to cooperate with #Profile anyway ( jenkins profile is active but test is still running ) .
#Profile has zero affect on test classes. Thus, you should simply remove that annotation.
If you want to enable a test class only if a given system property is present with a specific value, you could use #IfProfileValue.
However, in your scenario, you want to disable a test class if a given system property is present with a specific value (i.e., if spring.profiles.active contains jenkins).
Instead of implementing a custom ActiveProfileResolver, a more elegant solution would be to use a JUnit assumption to cause the entire test class to be ignored if the assumption fails.
This should work nicely for you:
import static org.junit.Assume.*;
// ...
#BeforeClass
public static void disableTestsOnCiServer() {
String profilesFromConsole = System.getProperty("spring.profiles.active", "");
assumeFalse(profilesFromConsole.contains("jenkins"));
}
Regards,
Sam (author of the Spring TestContext Framework)
I have to mock jerseyclient which is being created in Constructor of subjected service. Subjected service is System under test injected via Spring's #Autowired.
In constructor of the service client=client.create() method is written. We can't change this code(Although this is a code smell). I want to mock the jersey client but it is in constructor of the service. I am not able to mock this
sooo... long story short.. admitting you use mockito, in your src for test you should have an applicationcontext for your test.. usually we define one programmatically so, something along those lines..
import the .xml file you use for test purpose (in my case i imported the one for the mailserver, for the connection and for the authentication) instead of the one i use for the "local" environmnet. After then define a method to setup each and every of your service.
You might need to add a mock for your template resolver as well, but ultimately this all depends on your stack...
So based on your approach the final thing might be a bit different, but ultimately you're gonna do something along the lines of what i outline below:
#Configuration
#ImportResource(value = {
"classpath:applicationContext-jdbc-test.xml",
"classpath:applicationContext-ldap-test.xml",
"classpath:applicationContext-mail-test.xml"})
public class ApplicationTestContext {
#Bean
public ObjectMapperWrapper objectMapperWrapper() {
return Mockito.mock(ObjectMapperWrapper.class);
}
#Bean
public YourService yourService() {
return new YourServiceImpl();
}
}
Does any one know how to tackle this.
#RunWith(SpringJUnit4ClassRunner.class)
#RunWith(Parametrized.class)
#ContextConfiguration("/META-INF/blah-spring-test.xml")
public class BlahTest
..
so i want to have a spring nature test and at the same time want to have it parameterized to avoid code duplication ...
You can't use two runners as it noted in the commented post. You should use the Parameterized runner as use Spring's TestContextManager to load the Spring context.
#Before
public void before() throws Exception {
new TestContextManager(getClass()).prepareTestInstance(this);
}
As of Spring Framework 4.2, JUnit-based integration tests can now be executed with JUnit rules instead of the SpringJUnit4ClassRunner. This allows Spring-based integration tests to be run with alternative runners like JUnit’s Parameterized or third-party runners such as the MockitoJUnitRunner. See more details on spring doc.
Building upon John B's answer using TestContextManager, one can also call beforeTestMethod() and afterTestMethod() on it to better simulate SpringJUnit4ClassRunner's behaviour (for instance loading database with #Sql).
These methods require a Method parameter, so one can for instance take advantage of JUnit4's TestName rule to get the current test method's name and then retrieving it by reflection.
private static TestContextManager springTestContext
= new TestContextManager(BlahTest.class);
#Rule
public TestName testName = new TestName();
#Before
public void before() throws Exception {
springTestContext.prepareTestInstance(this);
springTestContext.beforeTestMethod(this,
getClass().getMethod(testName.getMethodName()));
}
#After
public void after() throws Exception {
springTestContext.afterTestMethod(this,
getClass().getMethod(testName.getMethodName()), null);
}
I have a test class that looks like
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/test-context.xml"})
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public abstract class TestClass {
#Rule #Resource public JUnitRuleMockery jMockContext;
public void test1() {
//Expectations and test
}
public void test2() {
//Expectations and test
}
}
and in test-context.xml I define the JUnitRuleMockery plus several mock objects through a factory-method, like
<bean id="mockContextFactory" class="MockContextFactory" />
<bean id="jMockContext" factory-bean="mockContextFactory" factory-method="getContext" scope="prototype" />
<bean id="firstMock" factory-bean="mockContextFactory" factory-method="getFirstMock" />
<bean id="secondMock" factory-bean="mockContextFactory" factory-method="getSecondMock" />
MockContextFactory is
public class MockContextFactory
{
private JUnitRuleMockery jUnitRuleMockery;
public MockContextFactory() {
jUnitRuleMockery = new JUnitRuleMockery();
jUnitRuleMockery.setThreadingPolicy(new Synchroniser());
}
public JUnitRuleMockery getContext() {
return jUnitRuleMockery;
}
public FirstMock getFirstMock() {
return jUnitRuleMockery.mock(FirstMock.class);
}
//others getter
}
In TestClass I have several test methods and, due to the annotations #DirtiesContext, I am expecting the Spring context to be reloaded after each test execution (since each test sets expectations on mock objects, I have to reload Spring context every time). See #DirtiesContext from here. However, it appears that the Spring context is not reloaded: in fact, entering in debug mode at the beginning of test2 (supposedly test1 has been executed earlier) I can see jMockContext still holding expectations, execution list and errors (if any) from test1.
So, to end up with few questions, does #DirtiesContext really cause Spring context to be reloaded (as I understood from Spring Docs) or did I misunderstand the annotation? In the first case, what am I doing wrong? In the latter case, how can I force Spring context to be reloaded for every test?
EDIT, to delimit the problem: I had a code like the sample above running from few days, then today I created a new test in which I added an expectation which failed. Then, I saw all the other tests in the class failing for the same reason (while they where green until today). Debugging, I found out that jMockContext was never cleared, which means all tests were adding expectations to the same pool: of course, as long as no expectation failed, that was transparent and I did not notice it (test1 adds and passes few expectations, test2 takes a not-empty pool of expectations ALREADY passed and adds its own so there was no problem), but I do not like the previous situation and I would like to start each test with no previous set expectations at all.
Here is my solution. I do not know if this is limited to Spring 3.2 or if it is a general misunderstanding, but simply using #DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) is not enough to cause the entire Spring context to be reloaded for each test. I had to add also the DirtiesContextTestExecutionListener in #TestExecutionListeners.
So, in the end, what worked for me was just to change the annotation of my TestClass to
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/test-context.xml"})
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
#TestExecutionListeners({DirtiesContextTestExecutionListener.class})
public abstract class TestClass
Nothing else has to change.
I have a junit 4 test class testing a DAO.
unit test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:/WEB-INF/applicationContext-db.xml",
"classpath:/WEB-INF/applicationContext-hibernate.xml",
"classpath:/WEB-INF/applicationContext.xml" })
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})
#DataSetLocation("test/java/com/yada/yada/dao/dbunit-general.xml")
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback = true)
#Transactional
public class RealmDAOJU4Test {
#Autowired
private DbUnitInitializer dbUnitInitializer;
#Autowired
private RealmDAO realmDAO;
#BeforeTransaction
public void setupDatabase() {
// use dbUnitInitializer to insert test data
}
#Test
public void testGetById() {
Integer id = 2204;
Realm realm = realmDAO.get(id);
assertEquals(realm.getName().compareToIgnoreCase(
"South Technical Realm"), 0);
assertEquals(8, realm.getRealmRelationships().size());
}
// more test methods annotated here
}
The #BeforeTransacation method runs before EVERY test method. What I would like to do is: use my DbUnitInitializer to load data into my database - ONCE when the class is created. Then have each test in the class do what it needs to do with the database, then roll back (not commit) it's changes. It seems over kill to re-insert all the same data from my test files before EVERY test. Is there a way to accomplish this?
or
Is the correct way to write these tests to completely load the database before EVERY test? If so, what function does the defaultRollback=true have in this situation?
thanks for helping me along in my thinking...
You need to use a TestExecutionListener and set up your database in the beforeTestClass method. See the Annotations section of the Testing chapter in the Spring user guide.