I have a case where I have a #Factory annotated class which creates a bean and invokes some code. I have enabled eager singleton initialization and the
bean factory method is invoked even though it is not used anywhere when the application is started. However for tests, the eager initialization does not work and the bean is not created :
Application :
public class Application {
public static void main(String[] args) {
Micronaut.build(args)
.eagerInitSingletons(true)
.mainClass(Application.class)
.start();
}
}
Config
#Factory
public class Config {
#Singleton
#Bean
public Response response() {
System.out.println("Invoked");
//invoking some code
return new Response("test");
}
}
and the test :
#MicronautTest(application = Application.class)
class ApplicationSpec extends Specification {
#Inject
EmbeddedApplication<?> application
void 'test it works'() {
expect:
application.running
}
}
so when the test is executed, the response method from Config class is not invoked even though eagerInitSingletons is enabled and it works when the application is started normally.
The question is : How to enable eager singleton initialization for micronaut tests?
Can you try using a custom context builder?
YourTest Class
#MicronautTest(contextBuilder = CustomContextBuilder.class)
Your CustomContextBuilder:
public class CustomContextBuilder extends DefaultApplicationContextBuilder {
public CustomContextBuilder() {
eagerInitSingletons(true);
}
}
Related
I'm trying to find any analogue of spring's #ContextConfiguration annotation in micronaut framework
Is there any way to run unit test in micronaut using custom application context?
My project is a library without main class.
I have #Factory with initialization of my beans.
#Factory
public class TestConfig {
#Singleton
public QueryParameterParser queryParameterParser() { }
#Singleton
public ConnectionHolder connectionHolder(DataSource dataSource) { }
#Singleton
public QueryExecutor queryExecutor(ConnectionHolder connectionHolder, QueryParameterParser parameterParser) { }
}
In spring I'd write these for using context in test:
#ContextConfiguration(classes = TestConfig.class)
public class FunctionTest {
#Autowired
private TransactionExecutor transactionExecutor;
The only way to do it in micronaut I've found is to create CustomContextBuilder:
#Introspected
public class CustomContextBuilder extends DefaultApplicationContextBuilder {
private TestConfig factory = new TestConfig();
public CustomContextBuilder() {
TestConfig.DataBase db = factory.db();
DataSource dataSource = factory.dataSource(db);
singletons(
db, dataSource,
queryParameterParser,
connectionHolder,
new MicronautFixturesTestExecutionListener()
);
}
and pass CustomContextBuilder to #MicronautTest annotation. It works but is too complicated to write code for instantiating every bean in CustomContextBuilder everytime.
Is there any way to pass my #Factory class to context and not to write all singletons?
I've tried package method and passed my #Factory package - but it didn't created context properly.
I have an application based on Spring 4.3.28 (i.e. not Spring Boot!) and I want to migrate my integration tests to Cucumber.
I’ve followed this tutorial and adapted it to plain Spring.
The tests I’ve written so far are working fine (Spring context is initialized etc.), but as soon as there are request-scoped beans involved, they stop working:
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you
referring to request attributes outside of an actual web request, or processing a
request outside of the originally receiving thread? If you are actually operating
within a web request and still receive this message, your code is probably running
outside of DispatcherServlet/DispatcherPortlet: In this case, use
RequestContextListener or RequestContextFilter to expose the current request.
I’ve created a small sample project
that tries to reproduce the problem.
There is one context configuration class called AppConfig:
#Configuration
public class AppConfig {
#Bean
#Scope("request“) // when this line is removed, the test succeeds
public ExampleService exampleService() {
return new ExampleService();
}
#Bean("dependency")
#Scope("request") // when this line is removed, the test succeeds
public String dependencyBean() {
return "dependency bean";
}
}
The ExampleService is request-scoped, and gets one request-scoped bean injected by #Autowired:
public class ExampleService {
#Autowired
#Qualifier("dependency")
String dependencyBean;
public String process() { return "I have a "+dependencyBean; }
}
For the tests, I have one Spring-annotated superclass:
#ContextConfiguration(classes = AppConfig.class)
#CucumberContextConfiguration
#WebAppConfiguration
public class TestBase {
#Autowired
public ExampleService underTest;
}
There’s also a plain Spring test that runs just fine:
#RunWith(SpringRunner.class)
public class ExampleServicePlainSpringTest extends TestBase {
#Test
public void whenProcessingDataThenResultShouldBeReturned() {
assertThat(this.underTest.process()).isEqualTo("I have a dependency bean");
}
}
The Cucumber test is executed by this test class stub:
#RunWith(Cucumber.class)
public class ExampleServiceCucumberTest extends TestBase {}
The actual cucumber step definitions are here:
public class CucumberStepDefinitions extends TestBase {
private String result;
#When("I process data")
public void iProcessData() {
result = this.underTest.process();
}
#Then("the result should be returned")
public void checkResult() {
assertThat(result).isEqualTo("I have a dependency bean");
}
}
The .feature file for Cucumber is in the src/test/resources directory under the same package name as the step definitions class:
Feature: Example
Scenario: Example service bean returns dependency
When I process data
Then the result should be returned
Usually when I encountered the „no thread-bound request found“ error, it was because the #WebAppConfiguration annotation was missing, or when I tried to inject a request-scoped bean into a non-request scoped bean. But that’s not the case here.
What am I doing wrong?
I was able to figure out how to resolve it; the updated code is in the github repository linked in the question.
When using the SpringRunner, the request context is initialized in a ServletTestExecutionListener that is implicitly added to the list of TestExecutionListeners for the test.
The initialization happens in the beforeTestMethod() method of that listener.
However, as #M.P.Korsanje correctly remarked in the comments (thanks!), Cucumber doesn't have test methods, so beforeTestMethod() is never executed.
My solution was to add a custom subclass of ServletTestExecutionListener as a TestExecutionListener that delegates the beforeTestClass() call to the beforeTestMethod():
public class ClassLevelServletTestExecutionListener extends ServletTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
super.beforeTestMethod(testContext);
}
#Override
public void afterTestClass(TestContext testContext) throws Exception {
super.afterTestMethod(testContext);
}
}
And in ExampleServiceCucumberTest:
#ContextConfiguration(classes = {AppConfig.class})
#CucumberContextConfiguration
#WebAppConfiguration
#TestExecutionListeners(ClassLevelServletTestExecutionListener.class)
// extend the Spring class to get the default TestExecutionListeners
public class TestBase extends AbstractJUnit4SpringContextTests {
#Autowired
public ExampleService underTest;
}
I'm using Spring annotation based configuration in my Play application.
Controllers and DAOs are Spring beans. Controller and DAO layers are defined with different Spring profiles and each layer could be disabled separately.
I'd like to test controller layer in isolation from DAO layer. I've disabled DAO profile and redefined each of DAO beans as a Mockito mock. From functional point of view it works fine, the only thing I don't like is defining mocks manually like this:
#Configuration
#Import(AppContext.class)
public class TestAppContext {
#Bean
public DaoA getDaoA(){
return mock(DaoA.class);
}
//... all dependencies are re-defined manually
}
Is there a way to define package (like with #ComponentScan annotation)
and get all beans in that package as mocks instead of real objects?
UPD:
I'm running tests with FakeApplication (https://www.playframework.com/documentation/2.0/api/java/play/test/FakeApplication.html), so context is started not in the test level, but inside fake application startup.
public class ControllerTest extends WithApplication {
#Before
public void setUp() throws Exception {
start(fakeApplication(new GlobalSettings(){
private ApplicationContext appContext;
public void onStart(Application app) {
appContext = new AnnotationConfigApplicationContext(TestAppContext.class);
}
#Override
public <A> A getControllerInstance(Class<A> clazz) throws Exception {
return appContext.getBean(clazz);
}
}));
}
...
}
I did it like this because I wan't to make the test more reliable and test how controller works in real environment:
#Test
public void testControllerMethod() {
Result result = route(fakeRequest(GET, "/controller/method"));
assertThat(result).is(...);
}
If the number of dependencies you need to mock is huge, you can also use spring-auto-mock.
#ContextConfiguration(classes = { AutoMockRegistryPostProcessor.class, RestOfClasses.class, ... })
#RunWith(SpringJUnit4ClassRunner.class)
public class YourTest {
...
}
As you are creating the ApplicationContext on your own, you can register the postprocessor programmatically:
public void onStart(Application app) {
appContext = new AnnotationConfigApplicationContext(TestAppContext.class);
appContext.getBeanFactory().addBeanPostProcessor(new AutoMockRegistryPostProcessor())
}
Mark your unit-test with #RunWith(SpringJUnit4ClassRunner.class)
Mark your tested class as #InjectMock
Mark you Dao class as #Mock
Make use of Mockito in your project
Im fairly new to Java Spring IoC and here's my problem
I have a FactoryConfig class with all beans and annotation #Configuration and #ComponentScan written as below.
import org.springframwork.*
#Configuration
#ComponentScan(basePackages="package.name")
public class FactoryConfig {
public FactoryConfig() {
}
#Bean
public Test test(){
return new Test();
}
//And few more #Bean's
}
My Test class has a simple Print method
public class Test {
public void Print() {
System.out.println("Hello Test");
}
}
Now in my Main Class Ive created an ApplicationContentext of FactoryConfig. (I'm expecting all of my #Beans in Factory config will be initialised. However, it returns null when I access the Test class using #Autowired
My Main Class
public class Main {
#Autowired
protected static Test _autoTest;
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ApplicationContext context =
new AnnotationConfigApplicationContext(FactoryConfig.class);
FactoryConfig config = context.getBean(FactoryConfig.class);
config.test().Print();
// _autoTest.Print(); <--- Im getting NULL Pointer Ex here
}
}
What is the correct way to #Autowire and use objects/beans? any clearer explanation would be much appreciated.
Only beans managed by Spring can have #Autowire annotations. Your main class is not managed by Spring: it's created by you and not declared in a Spring context: Spring doesn't known anything about your class, and doesn't inject this property.
You can just access in your main method the Test bean with :
context.getBean(Test.class).Print();
Usually, you get a "bootstrap" from the context, and call this bootstrap to start your application.
Moreover:
On Java, a method shouldn't start with an uppercase. Your Test class should have a print method, not Print.
If you start with Spring, you should maybe try Spring Boot
Spring does not manage your Main class, that's why you are getting Nullpointer Exception.
Using ApplicationContext to load beans, you can get your beans and access Methods as you are already doing -
ApplicationContext context =
new AnnotationConfigApplicationContext(FactoryConfig.class);
FactoryConfig config = context.getBean(FactoryConfig.class);
config.test().Print();
remove the static argument
protected Test _autoTest;
Your class
public class Test {
public void Print() {
System.out.println("Hello Test");
}
}
is not visible to Spring. Try adding an appropriate annotation to it, like #Component.
The reason is that your Main is not managed by Spring. Add it as bean in your configuration:
import org.springframwork.*
#Configuration
#ComponentScan(basePackages="package.name")
public class FactoryConfig {
public FactoryConfig() {
}
#Bean
public Test test(){
return new Test();
}
#Bean
public Main main(){
return new Main();
}
//And few more #Bean's
}
And then you can edit your main() as follows:
public class Main {
#Autowired
protected Test _autoTest;
public static void main(String[] args) throws InterruptedException {
ApplicationContext context =
new AnnotationConfigApplicationContext(FactoryConfig.class);
Test test = context.getBean(Test.class);
Main main = context.getBean(Main.class);
test.Print();
main._autoTest.Print();
}
}
I'm trying to set up a very simple implementation of weld in java SE.
I have the extension class:
public class MyExtension implements Extension {
void beforeBeanDiscovery(#Observes BeforeBeanDiscovery bbd) {
System.out.println("Starting scan...");
}
<T> void processAnnotatedType(#Observes ProcessAnnotatedType<T> annotatedType, BeanManager beanManager) {
System.out.println("Scanning type: " + annotatedType.getAnnotatedType().getJavaClass().getName());
}
void afterBeanDiscovery(#Observes AfterBeanDiscovery abd) {
System.out.println("Finished the scanning process");
}
public void main(#Observes ContainerInitialized event) {
System.out.println("Starting application");
new Test();
}
}
I then have a simple class that I want to inject:
public class SimpleClass {
public void doSomething() {
System.out.println("Consider it done");
}
}
And lastly the class I want to inject it in:
public class Test {
#Inject
private SimpleClass simple;
#PostConstruct
public void initialize() {
simple.doSomething();
}
#PreDestroy
public void stop() {
System.out.println("Stopping");
}
}
The resulting output is:
80 [main] INFO org.jboss.weld.Version - WELD-000900 1.1.10 (Final)
272 [main] INFO org.jboss.weld.Bootstrap - WELD-000101 Transactional services not available. Injection of #Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Starting scan...
Scanning type: test.Test
Scanning type: test.SimpleClass
Scanning type: test.MyExtension
640 [main] WARN org.jboss.weld.interceptor.util.InterceptionTypeRegistry - Class 'javax.ejb.PostActivate' not found, interception based on it is not enabled
640 [main] WARN org.jboss.weld.interceptor.util.InterceptionTypeRegistry - Class 'javax.ejb.PrePassivate' not found, interception based on it is not enabled
Finished the scanning process
Starting application
I would expect the simple class to be injected when Test() is constructed and the postconstruct method to be called which should output the expected text.
What exactly am I doing wrong?
There's two issues with your code:
Problem 1:
CDI does not manage beans created with new. For the most part you need to #Inject a bean in order for its life cycle to be managed by the container
Problem 2:
For the most part, you cannot inject bean instances into observers of container events. That's because the events are firing as the container is being initialized, aka before it can actually begin managing object life cycles.
You could hook the container initializer observer directly into your Test class. Something like this:
public class SimpleClass {
public void doSomething() {
System.out.println("Consider it done");
}
#PostConstruct
public void initialize() {
System.out.println("Starting");
}
#PreDestroy
public void stop() {
System.out.println("Stopping");
}
}
public class Test {
#Inject
private SimpleClass simple;
public void main(#Observes ContainerInitialized event) {
System.out.println("Starting application");
simple.doSomething();
}
}
What you're doing wrong is calling new Test(). This constructs a new instance of Test, but in the back of CDI. For CDI to inject your Test instance, CDI has to create it itself.
See the documentation for how to boostrap Weld in a Java SE environment.
Create a utils class with #ApplicationScoped. This class can produce objects of every type. In your case this is just like this:
#Produces
static SimpleClass generateSimpleClass(){
return new SimpleClass();
}
Otherwise, if simpleclass for you is going to be a unique class in the application, set its class as #ApplicationScoped. Problem is that weld does not know that the class belongs to the container if there is neither annotation nor producer