I have an Integration test as shown below, and I want to rollback the changes to the database after going through the test cases. Now my question is is there a way to prevent default rollback from happening after each test case and have a roll back once all the test cases are done.
After surfing a bit I found that TestNG can be helpful, but I don't want to use that. Is there any other alternative?
#TransactionConfiguration(transactionManager = "myTransactionManager", defaultRollback = true)
public class TestDependencies extends testBase {
#Test
public void testSetupData() throws SQLException, Exception{
//Some initial setup code.
}
#Test
public void testFunctionality throws Exception{
//here i will further test some more functionality
}
}
If all your test cases that require rollback are in one class, the junit #afterclass annotation will run this method after all #test methods are executed.
#AfterClass
public static void Cleanup() {
txManager.rollback();
}
txManager should be wired up to your DataSourceTransactionManager bean.
Related
So I am making my first tests in spring boot and I came across a problem. When I execute my tests, the values are actually getting deleted. I would prefer to mock this so that the values do not get deleted.
My test class:
#SpringBootTest
#AutoConfigureMockMvc
public class PartyEndpointTest {
#Autowired
private MockMvc mockMvc;
#Test
#DisplayName("Should Not give access to endpoint")
public void ShouldNotGiveAccess() throws Exception{
mockMvc.perform(MockMvcRequestBuilders.get("/parties"))
.andExpect(MockMvcResultMatchers.status().is(401));
}
#Test
#WithMockUser("JLardinois")
#DisplayName("Should respond with not found request")//is 401 because first authorized then check if its found
public void shouldNotFindRequest() throws Exception{
mockMvc.perform(MockMvcRequestBuilders.get("/partyy")).andExpect(MockMvcResultMatchers
.status().is(404));
}
#Test
#WithMockUser("JLardinois")
public void ShouldFindRequest() throws Exception{
mockMvc.perform(MockMvcRequestBuilders.get("/parties")).andExpect(MockMvcResultMatchers
.status().isOk());
}
#Test
#WithMockUser("JLardinois")
public void DeleteParty() throws Exception{
mockMvc.perform(MockMvcRequestBuilders.delete("/parties/4")).andExpect(MockMvcResultMatchers
.status().isOk());
}
In this test class, my delete method from my controller gets tested, but the entity with ID 4 in my database gets deleted when I run this. I do not want this.
Can anyone help me how to mock this, so that nothing gets deleted from my database?
Thanks in advance!
Firstly, you should not run tests on your real database. Tests should not be related to the environment in any way. If you want integration tests with database, pay attention to testcontainers, you can choose framework and database what you want. Your test configuration should not contain the actual base values, create test configuration (application.yaml in src/test/resources) if you don't have it.
If you don't want integration test, mock your repository:
#MockBean
private MyRepository myRepository;
#Before
public void init() {
Mockito.doNothing().when(myRepository).delete(any());
}
I am working on creating integration test for a service class i am testing and I needed to mock the dao for one of the test methods. the problem is when i run the tests together some of my tests fail but when i run them individually the tests past. If i remove the mockito part all my tests pass when i run them all at once. any insight on this is appreciated
below is my code:
// here is my Service class
public class Service {
Dao dao;
public Dao getDao() {
return dao;
}
public void setDao(Dao dao) {
this.dao = dao;
}
}
//here is my integ test
#Category(IntegrationTest.class)
#RunWith(SpringRunner.class)
public class Test{
#Rule
public ExpectedException thrown = ExpectedException.none();
#Autowired
#Qualifier(Service.SERVICE_NAME)
protected Service service;
#Before
public void setUp() {
assertNotNull(service);
}
#Test
public void testDoSomethingOne() throws Exception {
Dao dao = Mockito(Dao.class)
service.setDao(dao)
boolean flag = service.doSomething();
Assert.assertTrue(flag);
}
#Test
public void testDoSomethingTwo() throws Exception {
Integer num = service.doSomething();
Assert.assertNotNull(num);
}
The test method testDoSomethingOne() sets the mock dao for the service instance which it retains for rest of the tests.
Annotate the method testDoSomethingOne() with #DirtiesContext to get a fresh context associated with the subsequent test method.
Test annotation which indicates that the ApplicationContext associated
with a test is dirty and should therefore be closed and removed from
the context cache.
Use this annotation if a test has modified the
context — for example, by modifying the state of a singleton bean,
modifying the state of an embedded database, etc. Subsequent tests
that request the same context will be supplied a new context.
You can get the dao before each test and assign it back to service after the test
something like this:
private static Dao dao;
#Before
public void setUp() {
if(dao == null) {
dao = service.getDao();
}
}
#After
public void tearDown() {
service.setDao(dao);
}
If it is a integration test you should not mock your daos, the recommended way is to use a in memory database like H2. The spring folks already provide the annotation #DataJpaTest that creates the database for you.
You can use the #DataJpaTest annotation to test JPA applications. By default, it scans for #Entity classes and configures Spring Data JPA repositories. If an embedded database is available on the classpath, it configures one as well. Regular #Component beans are not loaded into the ApplicationContext.
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test
Currently for tests I'm using TestExecutionListener and it works just perfect
public class ExecutionManager extends AbstractTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
System.out.println("beforeClass");
}
#Override
public void afterTestClass(TestContext testContext) throws Exception {
System.out.println("afterClass");
}
}
Test classes:
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners(ExecutionManager.class)
public final class TC_001 {
#Test
public void test() {
System.out.println("Test_001");
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners(ExecutionManager.class)
public final class TC_002 {
#Test
public void test() {
System.out.println("Test_002");
}
}
When I include those tests in test suite, beforeTestClass(TestContext testContext) and afterTestClass(TestContext testContext) methods are executed for each test class, what is quite logical:
#RunWith(Suite.class)
#Suite.SuiteClasses({
TC_001.class,
TC_002.class
})
public final class TS_001 {
}
Is there anything like SuiteExecutionListener (TestExecutionListener for suites)?
Basically I need non-static #BeforeClass and #AfterClass for suite
OR
In ExecutionListener I need to find out what class has been launched: case or suite. For this purpose I can:
analyze StackTrace and get calling class
use Reflection.getCallerClass(int i) (which is deprecated)
pass caller class to ExecutionManager (By the way, how can I do that? Is it possible to put Object into TestContext like in Android Bundle?)
But I don't really like those solutions. SuiteExecutionListener is much more preferable
Thank you
No, there is unfortunately no such thing as a SuiteExecutionListener in the Spring TestContext Framework (TCF).
The TCF does not integrate with JUnit 4 at the suite level.
If you want to store something in the TestContext, that's not a problem. TestContext implements org.springframework.core.AttributeAccessor, so you can store attributes in the TestContext. Note, however, that the lifecycle of a given TestContext is tied to a test class.
I would like to register some web scopes to the spring context in my #BeforeTest method. But it turns out that spring context is still null at that point.
The test runs fine though, if I change into #BeforeMethod. I wonder how I can access the context in #BeforeTest, because I don't want the scope registration code to be repeated for each test methods.
Below are my code snippets.
public class MyTest extends MyBaseTest {
#Test public void someTest() { /*...*/ }
}
#ContextConfiguration(locations="/my-context.xml")
public class MyBaseTest extends AbstractTestNGSpringContextTests {
#BeforeTest public void registerWebScopes() {
ConfigurableBeanFactory factory = (ConfigurableBeanFactory)
this.applicationContext.getAutowireCapableBeanFactory();
factory.registerScope("session", new SessionScope());
factory.registerScope("request", new RequestScope());
}
/* some protected methods here */
}
Here's the error message when running the test:
FAILED CONFIGURATION: #BeforeTest registerWebScopes
java.lang.NullPointerException
at my.MyBaseTest.registerWebScopes(MyBaseTest.java:22)
Call springTestContextPrepareTestInstance() in your BeforeTest method.
TestNG runs #BeforeTest methods before #BeforeClass methods. The springTestContextPrepareTestInstance() is annotated with #BeforeClass and sets up the applicationContext. This is why the applicationContext is still null in a #BeforeTest method. #BeforeTest is for wapping a tagged group of tests. (It does not run before each #Test method, so it's a bit of a misnomer).
Instead of using #BeforeTest, you should probably use #BeforeClass (which is run once, before the first #Test in the current class). Be sure it depends on springTestContextPrepareTestInstance method, as in
#BeforeClass(dependsOnMethods = "springTestContextPrepareTestInstance")
public void registerWebScopes() {
ConfigurableBeanFactory factory = (ConfigurableBeanFactory)
this.applicationContext.getAutowireCapableBeanFactory();
factory.registerScope("session", new SessionScope());
factory.registerScope("request", new RequestScope());
}
The #BeforeMethod works, too (as you mentioned) because they run after #BeforeClass methods.
Is it possible to run an external command before running tests in a given JUnit file? I run my tests using the Eclipse's Run command. Using JUnit 4.
Thanks.
Very vague question. Specifically, you didn't mention how you are running your JUnit tests. Also you mentioned 'file', and a file can contain several JUnit tests. Do you want to run the external command before each of those tests, or before any of them are executed?
But more on topic:
If you are using JUnit 4 or greater then you can tag a method with the #Before annotation and the method will be executed before each of your tagged #Test methods. Alternatively, tagging a static void method with #BeforeClass will cause it to be run before any of the #Test methods in the class are run.
public class MyTestClass {
#BeforeClass
public static void calledBeforeAnyTestIsRun() {
// Do something
}
#Before
public void calledBeforeEachTest() {
// Do something
}
#Test
public void testAccountCRUD() throws Exception {
}
}
If you are using a version of JUnit earlier than 4, then you can override the setUp() and setUpBeforeClass() methods as replacements for #Before and #BeforeClass.
public class MyTestClass extends TestCase {
public static void setUpBeforeClass() {
// Do something
}
public void setUp() {
// Do something
}
public void testAccountCRUD() throws Exception {
}
}
Assuming you are using JUnit 4.0, you could do the following:
#Test
public void shouldDoStuff(){
Process p = Runtime.getRuntime().exec("application agrument");
// Run the rest of the unit test...
}
If you want to run the external command for every unit test, then you should do it in the #Before setup method.