No transactional EntityManager found, is your test running in a transactional? - spring

I am writing tests for a repository, but BeforeAll annotation causes
java.lang.IllegalStateException: No transactional EntityManager found, is your test running in a transactional?
error. If I change it to BeforeEach the tests work, but that's not very efficient, since the same record is repeatedly written into the database. How can I fix this?
My test class:
#DataJpaTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#ActiveProfiles("testing")
class RepositoryTest {
#Autowired
lateinit var entityManager: TestEntityManager
val data = Data(...)
#BeforeAll
#Transactional
fun setup() {
entityManager.persist(data)
entityManager.flush()
}
#Test
func someTest() {
assertEquals(1,1)
}
}

According to this question (and my own experience) #Transactional has no effect on methods annotated with #BeforeAll and similar. To get transactional behaviour, you need to add #Transactional to all the relevant #Test methods, or to the class as a whole (which then applies to every test method).

I think your problem is that #BeforeAll runs before the Dependency Injection. So your EntityManager is still null when you are trying to call entityManager.persist(data). Using a Constructor will result in the same problem.

Related

MeterRegistry counter test case failing

I have implemented Micrometer Prometheus counter in my service by injecting MeterRegistry and incrementing the count as shown below, and I have written a test case as well, but when I am running the test case, I am getting:
"java.lang.NullPointerException: Cannot invoke
"io.micrometer.core.instrument.MeterRegistry.counter(String,
String[])" because "this.meterRegistry" is null".
Service file:
#Autowired
private MeterRegistry meterRegistry;
public void counterIncrement() {
meterRegistry.counter("test_count").increment();
}
Test case file:
#MockBean
private MeterRegistry registry;
#Test
void testCounter() {
// invoking counterIncrement();
}
How do you create your class under test?
Since the registry is never instantiated, something seems up with how you setup your test.
Check that you are using the #MockBean in the correct way. This will replace the bean in the application context and if you do not spin up a spring context in your test, it will not work. See this post for more info.
A different approach would be to use #Mock and inject the registry in the constructor, example:
#ExtendWith(MockitoExtension.class)
public class MyServiceTest {
#Mock
private MeterRegistry registry;
private MyService myService;
#BeforeEach
void setup() {
myService = new MyService(registry);
}
#Test
void testCounter() {
var counter = mock(Counter.class);
given(registry.counter(any(String.class))).willReturn(counter);
myService.counterIncrement();
}
You can test metrics without Mockito using SimpleMeterRegistry
#Test
void testCounter() {
var meterRegistry = new SimpleMeterRegistry();
Metrics.addRegistry(meterRegistry);
// invoke counterIncrement();
var actual = meterRegistry.counter("test_count").count();
assertEquals(1.0d, actual);
}
Depending on which junit version you are using you need to add the annotation to your test class. Junit 5: #ExtendWith(MockitoExtension.class) or for Junit 4: #RunWith(MockitoJUnitRunner.class)
Depending on the test and the service there are several ways to deal with the missing MeterRegistry.
If you use a spring context in your test, try to use a test configuration to create the MeterRegistry bean.
If your test uses some Mock framework, you could mock the MeterRegistry as suggested by by #Hans-Christian.
If you simply make the member meterRegistry non-private. You could set it to a SimpleMeterRegistry in some setup method, anotated with #BeforeEach as suggested by #checketts in the comments.
If mocking the meter registry gets complicated, you could easily build and use some factory that provides the registry and mock this factory. A very easy factory will do, e.g. a spring #Component with an autowired MeterRegistry and some public getter for the factory.
You could use the factory method pattern as described in wikipedia to get the MeterRegistry, overwrite the factory method in a subclass of your service and use this subclass in the test. (Note that the gang of four did use a static factory method, you'll need a non-static method.)
I favour solution 3 but would use solution 1 whenever appropriate. I've added solutions 4 and 5 just because there might be some additional reasons and special cases that make these solutions a good choice. If so, I prefer 4 over 5.

How to get Hibernate Envers with Spring integration testing?

Is there some way to get Hibernate Envers to run immediately on the call to save or update instead of going at the end of the transaction ?
I have a #Transactional annotation on my (effectively end-to-end test). Since the code doesn't contain test methods I'm unable to put "flush" or whatever in it, (short of editing non-test code, which is not the desire).
I'm not sure how to get Envers log working on the calls. I need it to work as I'm using the Envers audit tables to check old entries at runtime, and would like to create test cases for this functionality.
I have the following code for unit testing :
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration("/src/webapp")
#EnableWebMvc
#Transactional
#TestPropertySource(locations= {"classpath:/config/common.properties"}, properties = {"..."})
#ContextConfiguration(locations = {"..."})
public class Test {
#Autowired
private WebApplicationContext wac;
#Autowired
private UserDetailsService detailsService;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.build();
}
...
}

Spring boot #SpyBean causing test suite to error probably due to issue with context not being reset

I have an issue with a spring integration test.
The behavior:
When I run the test below in isolation, it is in success.
However, when all tests are run, many of them including the one below are in error.
When I ignore the test below and run all test, all are in success.
I haven't included the error stacktrace because it is highly related to our business logic and I suspect the error is related to my usage of spring boot test #SpyBean.
Here is the test:
#RunWith(SpringRunner.class)
#ActiveProfiles(profiles = "test")
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
...
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private DataKeyStore dataKeyStore;
#SpyBean
private TokenTools tokenTools;
...
#Test
public void myTest() throws Exception {
doReturn("someGeneratedToken")
.doReturn("someGeneratedToken")
.doCallRealMethod()
.when(tokenTools)
.createToken(any(TokenProfile.class), anyString(), anyString());
...
Please note that DataKeyStore is a dependency of TokenTools.
As I said above, I suspect tests are stepping on each other and my #SpyBean somehow leaks on other test classes...
My question is how can I make sure this test does not step on the other tests? I have tried the #DirtiesContext annotation to no avail...
Also what puzzles me is that the #SpyBean is already reset (as per the documentation/javadoc).
Can anyone please help?
edit: Using my IDE to debug the tests indicates that TokenTools is instantiated only twice for all tests: once at the initialization of tests and a second time for creating the #SpyBean for the test above. The remainder of tests run after the test above use the second instance i.e. the #SpyBean instance...
I recently ran into the same issue. Make sure to set the right classMode for your
#DirtiesContext annotation.
By default, #DirtiesContext will reset the #SpyBean after the complete test class. You probably want to reset it before or after each test method.
So add #DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) or #DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) to your test class.
I can confirm that #DirtiesContext didn't work for us as well. We had problems initialize DB (using Liquibase) for new context after old context was closed (by #DirtiesContext annotation).
We ended up naming Spring test context differently for tests that are faking some bens:
E.g.:
#RunWith(SpringRunner.class)
#SpringBootTest
#ContextConfiguration(classes = SpringBootApp.class, name = "mainContext")
public class TestThatDoesntFakeBeans(){
}
#RunWith(SpringRunner.class)
#SpringBootTest
#ContextConfiguration(classes = SpringBootApp.class, name = "contextWithFakeBean")
public class TestThatFakeBeans(){
#SpyBean
//...
}
This way there is separate Spring context created for each name. Contexts with same name are reused by tests. But of course you need to make sure that tests with same context name doesn't affect each other.
#SpyBean seems to not be reset after each test which leads to unusual behavior. I would suggest using Mockito #Spy instead and check if the problem still persists.
import org.mockito.Spy
....
#RunWith(SpringRunner.class)
#ActiveProfiles(profiles = "test")
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
...
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private DataKeyStore dataKeyStore;
#Spy
private TokenTools tokenTools;
...
#Test
public void myTest() throws Exception {
doReturn("someGeneratedToken")
.doReturn("someGeneratedToken")
.doCallRealMethod()
.when(tokenTools)
.createToken(any(TokenProfile.class), anyString(), anyString());
...

Mock an Autowired ExecutorService

Abstract:
I have a Spring #Component that uses an autowired ExecutorService as a work pool. I'm using JUnit and Mockito to test the functionality of the component and I need to mock that Executor Service. This has been trivial for other autowired members - a generic helper, and a DAO layer for instance are easily mocked, but I need a real Executor Service.
Code:
#RunWith(MockitoJUnitRunner.class)
public class MadeUpClassNameTest{
#Mock
private ExecutorService executor;
#Before
public void initExecutor() throws Exception{
executor = Executors.newFixedThreadPool(2);
}
#InjectMocks
private ASDF componentBeingAutowired;
...
This alone doesn't work, the results of invokeAll() is always an empty list.
Attempting to more explicitly mock the executor method also doesn't work...
#Test
public void myTestMethod(){
when(executor.invokeAll(anyCollection()))
.thenCallRealMethod();
...
}
I get the cryptically worded exception:
You cannot use argument matchers outside of verification or stubbing.
(I thought this was a stubbing ?)
I could provide a thenReturn(Answer<>) method, but I'd like to make sure that the code actually works with an executor, a fair bit of the code is devoted to mapping the results of Futures.
Problem
How do I provide a real (or functionally usable mock) Executor Service ? Alternatively, is my difficulty in testing this component a sign that this is a poor design in need of refactoring, or possibly a bad test scenario ?
Notes
I want to stress that my problem is NOT getting Mockito or Junit set up. Other mocks and tests work correctly. My problem is specific only to the particular mock above.
Using: Junit 4.12, Mockito 1.10.19, Hamcrest 1.3
I think the following code runs after the Mock is injected.
#Before
public void initExecutor() throws Exception{
executor = Executors.newFixedThreadPool(2);
}
This causes your local copy of executor to be set, but not the one that is injected.
I would recommend using constructor injection in on your componentBeingAutowired and create a new one in your unit test and exclude Spring dependencies. Your test could then look like something below:
public class MadeUpClassNameTest {
private ExecutorService executor;
#Before
public void initExecutor() throws Exception {
executor = Executors.newFixedThreadPool(2);
}
#Test
public void test() {
ASDF componentBeingTested = new ASDF(executor);
... do tests
}
}
Another way is to use ReflectionTestUtils to inject the executor
#Before
public void initExecutor() {
ReflectionTestUtils.setField(componentBeingAutowired, "executor", Executors.newFixedThreadPool(2);
}
You can use the #Spy annotation.
#RunWith(MockitoJUnitRunner.class)
public class MadeUpClassNameTest{
#Spy
private final ExecutorService executor = Executors.newFixedThreadPool(2);
....
}
You can use the #Spy annotation.
#RunWith(MockitoJUnitRunner.class)
public class MadeUpClassNameTest{
#Spy
private final ExecutorService executor = Executors.newFixedThreadPool(2);
#Test
...
}

How do i write Junit4 tests without Spring transactional test support?

I would like to test transaction rollbacks in my application service. As a result i do not want to use spring's AbstractTransactionalJUnit4SpringContextTests with the #Transactional annotation as that wraps my test method in a transaction.
I know spring also offers AbstractJUnit4SpringContextTests for tests without transactions. However i need to have some transactions to save data into my database and also query data for assertions after running the service under test.
How can i write a Junit 4 spring transactional test without the default transaction test management?
Here is the answer to your question ;
#ContextConfiguration(value = "/applicationContext.xml")
public class JPASpringTest extends AbstractJUnit4SpringContextTests {
#PersistenceContext(unitName="jpadenemelocal")
EntityManager entityManager;
#Autowired
protected PlatformTransactionManager transactionManager;
#Test
public void testInsertRolManyToMany() {
TransactionStatus status = transactionManager.getTransaction(null);
// your code
transactionManager.commit(status);
}
}
The spring docs should cover this in their testing chapter
What you might want is to configure your test without the default TransactionalTestExecutionListener like this
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class,DirtiesContextTestExecutionListener.class})
public class SimpleTest {
#Test
public void testMethod() {
// execute test logic...
}
}

Resources