Junit5 has introduced #TestInstance annotation to manage the lifecycle and reuse of application context.
How does this relate to the existing #DirtiesContext mechanism?
I couldn't find anything that compares the practical use of these two.
Is #TestInstance meant to replace the #DirtiesContext?
Is it using #DirtiesContext under the hood?
Related
I was searching for the difference between the #Configuration vs #SpringBootConfiguration. I found many articles mentioned "As per the Spring documentation, #SpringBootConfiguration is just an alternative to the Spring standard #Configuration annotation. The only difference between the two is that the #SpringBootConfiguration allows the configuration to be found automatically".
So what does it mean by #SpringBootConfiguration allows the configuration to be found automatically? If we use the #Configuration for a class that contains #Bean annotated methods, Spring will create instantiation for those beans as well. Can anybody explain this to me clearly?
Because this question was driving me a little crazy and this was the first StackOverflow page I found, which didn't resolve the issue for me, I'm going to try to explain my findings:
#SpringBootApplication is a specialisation of #SpringBootConfiguration, which is a specialisation of #Configuration.
You may only have 1 #SpringBootConfiguration, which means you can't have both a #SpringBootConfiguration and a #SpringBootApplication in your application.
"#SpringBootConfiguration allows the configuration to be found automatically" means you don't have to do anything to have this (and therefore #SpringBootApplication) found. Other #Configuration classes are generally discovered by #ComponentScan
An extra advantage over #Configuration, is that it will be discovered by #StringBootTest.
Just open https://github.dev/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-docs/src/docs/asciidoc and search for SpringBootConfiguration you will find some information about it.
such as
#SpringBootConfiguration: enable registration of extra beans in the
context or the import of additional configuration classes. An
alternative to Spring’s standard #Configuration that aids
configuration detection in your integration tests.
and
Detecting Test Configuration If you are familiar with the Spring Test
Framework, you may be used to using #ContextConfiguration(classes=…)
in order to specify which Spring #Configuration to load.
Alternatively, you might have often used nested #Configuration classes
within your test.
When testing Spring Boot applications, this is often not required.
Spring Boot’s #*Test annotations search for your primary configuration
automatically whenever you do not explicitly define one.
The search algorithm works up from the package that contains the test
until it finds a class annotated with #SpringBootApplication or
#SpringBootConfiguration. As long as you structured your code in a
sensible way, your main configuration is usually found.
I need to mock a static method. I know of two tools to help do this: PowerMockito and JMockit, both of which require usage of the #RunWith annotation. However, I've already used #RunWith for SpringRunner to set up some #Autowired dependencies, and it seems you can't use #RunWith twice.
I see that PowerMockito has a PowerMockRunnerDelegate, which looks promising. But for various reasons, I'm stuck using JMockit for now. Is there a JMockit equivalent for this?
I essentially need to mock a static method and set up #Autowired dependencies for my test at the same time.
It looks like I can circumvent the need to use any specialized static mocking tool by wrapping the static method call.
The latest version of jmockit (1.49) does not utilize the #RunWith annotation. Instead, it has you setup a javaagent as a vmarg. There's full documentation on the jmockit site: https://jmockit.github.io/tutorial/Introduction.html#runningTests. I'd definitely encourage you to use JMockIt rather than the EasyMock+PowerMock combo, JMockIt is self-contained and handles statics naturally.
I have a problem getting Spring Boot 2.0.5 to work nicely with Kotlintest 3.1.10.
I made a test project illustrating the problem I have.
The project is a Spring Boot 2 application
with two entities, ShoppingOrder and OrderLine (to be totally unimaginative).
There is also a test case ShoppingOrderSpec which just tests the mapping by storing and retrieving the Order.
The testcase is configured like this:
#ExtendWith(SpringExtension::class)
#Transactional
#SpringBootTest
class ShoppingOrderSpec : WordSpec() {
override fun listeners() = listOf(SpringListener)
The test case is using the SpringExtension
by Spring to hook into the JUnit 5 engine. It also uses the SpringListener and Wordspec from Kotlintest to structure the tests
and do the assertions.
The SpringListener correctly autowires the dependencies, but somehow the transaction is not being created.
Running the testcase gives the following stack-trace:
2018-10-12 10:54:14.329 INFO 59374 --- [intest-engine-0] com.example.demo.ShoppingOrderSpec : Started ShoppingOrderSpec in 4.478 seconds (JVM running for 7.421)
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.demo.ShoppingOrder.lines, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:582)
...
at com.example.demo.ShoppingOrderSpec$1$1.invoke(ShoppingOrderSpec.kt:35)
at com.example.demo.ShoppingOrderSpec$1$1.invoke(ShoppingOrderSpec.kt:19)
So, somehow the org.springframework.transaction.annotation.Transactional annotation does not seem to work,
as removing the annotation, just gives the same response.
Anyone any ideas how to get the #Transactional being applied and respected?
You can't use JUnit Jupiter extensions with KotlinTest as they are different engines. Junit Jupiter is an implementation on top of Junit Platform, like KotlinTest is, but anything written specifically for Jupiter won't work with KotlinTest. Anything written for Junit Platform should work however.
Unfortunately, the naming choices by the JUnit team are poor imo, and so people think JUnit Jupiter is the same thing as JUnit Platform.
Anyway, those
#ExtendWith(SpringExtension::class)
#Transactional
#SpringBootTest
extensions are not going to mean anything to KotlinTest, anymore than they would for Spek or whatever. ExtendWith is a Jupiter specific annotation that tells it to use the SpringExtension class. The KotlinTest equivilent is SpringListener which you've already wired in.
I'm not sure if #SpringBootTest will be picked up or not by Spring. Support may need to be added for that depending on what it does.
Finally #Transactional works by creating proxies on the methods, but since in more advanced testing frameworks like KotlinTest, the test containers are not methods, but just arbitrary functions, it won't be able to intercept.
I think in this case, you might need to create a proper method and annotate that, or try using the AnnotationSpec rather than StringSpec or whatever other spec base class you are using, which uses actual methods that you could annotate.
What's the recommended way to run a spring boot test where only the one subject under test is configured in the context.
If I annotate the test with
#RunWith(SpringRunner.class)
#SpringBootTest(properties = "spring.profiles.active=test")
#ContextConfiguration(classes = MyTestBean.class)
Then it seems to work - the test passes, the context starts quickly and seems to only contain the bean that I want. However, this seems like an incorrect use of the #ContextConfiguration(classes = MyTestBean.class) annotation. If I understand correctly the class that I reference is supposed to be a Configuration class, not a regular spring service bean or component for example.
Is that right? Or is this indeed a valid way to achieve this goal? I know there are more complex examples like org.springframework.boot.test.autoconfigure.json.JsonTest which use #TypeExcludeFilters(JsonExcludeFilter.class) to control the context - but this seems overkill for my use case. I just want a context with my one bean.
Clarification
I know that I can just construct the one bean I am testing as a POJO without a spring context test and remove the three annotations above. But in my precise use case I am actually reliant on some of the configuration applied to the context by settings in the application-test.properties file - which is why I've made this a Spring Boot test with a profile set. From my perspective this isn't a plain unit test of a single class in isolation of the spring context configuration - the test is reliant on certain configuration being applied (which is currently provided by the spring boot app properties). I can indeed just test the components as a POJO by creating a new instance outside of a spring context, I'm using constructor injection making the providing of necessary dependencies simple but the test does rely on things like the log level (the test actually makes assertions on certain logs being produced) which requires that the log level is set correctly (which is currently being done via logging.level.com.example=DEBUG in a properties file which sets up the spring context).
For starters, reading the documentation first (e.g., the JavaDoc linked below in this answer) is a recommend best practice since it already answers your question.
If I understand correctly the class that I reference is supposed to be
a Configuration class, not a regular spring service bean or
component for example.
Is that right?
No, that's not completely correct.
Classes provided to #ContextConfiguration are typically #Configuration classes, but that is not required.
Here is an excerpt from the JavaDoc for #ContextConfiguration:
Annotated Classes
The term annotated class can refer to any of the following.
A class annotated with #Configuration
A component (i.e., a class annotated with #Component, #Service, #Repository, etc.)
A JSR-330 compliant class that is annotated with javax.inject annotations
Any other class that contains #Bean-methods
Thus you can pass any "annotated class" to #ContextConfiguration.
Or is this indeed a valid way to achieve this goal?
It is in fact a valid way to achieve that goal; however, it is also a bit unusual to load an ApplicationContext that contains a single user bean.
Regards,
Sam (author of the Spring TestContext Framework)
It is definitely a reasonable and normal thing to only test a single class in a unit test.
There is no problem including just one single bean in your test context. Really, a #Configuration is (typically) just a collection of beans. You could hypothetically create a #Configuration class just with MyTestBean, but that would really be unnecessary, as you can accomplish doing the same thing listing your contextual beans with #ContextConfiguration#classes.
However, I do want to point out that for only testing a single bean in a true unit test, best practice ideally leans towards setting up the bean via the constructor and testing the class that way. This is a key reason why the Spring guys recommend using constructor vs. property injection. See the section entitled Constructor-based or setter-based DI of this article, Oliver Gierke's comment (i.e. head of Spring Data project), and google for more information. This is probably the reason you're getting a weird feeling about setting up the context for the one bean!
You can also use ApplicationContextRunner to create your context using a test configuration of your choice (even with one bean if you like, but as other people have already mentioned for one bean it's more reasonable to use the constructor the classical way without using any spring magic).
What I like this way of testing is the fact that test run very fast since you don't load all the context. This method is best used when the tested bean doesn't have any Autowired dependencies otherwise it's more convenient to use #SpringBootTest.
Below is an example that illustrates the way you can use it to achieve your goal:
class MyTest {
#Test
void test_configuration_should_contains_my_bean() {
new ApplicationContextRunner()
.withUserConfiguration(TestConfiguration.class)
.run(context -> {
assertThat(context.getBean(MyTestBean.class)).isNotNull();
});
}
#Configuraiton
public static class TestConfiguration {
#Bean
public MyTestBean myTestBean(){
new MyTestBean();
}
}
}
Im working with the Spring Framework 3.0.5 and Spring Security 3.0.5 and Ive got questions to the aspect orientated programming. At the moment Im trying to figure out the disadvantages and advantages of aspect orientated programming. Of course, I know them in theory: I can avoid redundant code, I only have to make changes in the aspect, not everywhere in the code and so on. But I still got some questions:
The disadvantage I found out:
I wrote a sample application using aspects with Spring AOP. I configured an Aspect with Annotations (#Pointcut, #Before, #Aspect and so one). The methods that triggered the aspect (which were part of a Pointcut of course) were of course part of a different class and not annotated with anything.
=> I really think that one big disadvantage is that when watching those methods of the other class it was not clear that they trigger an aspect. They needed no annotations or anything else, they were just mentioned in the pointcut of the aspect. (I really hope you understand what I mean). So thats why I think that AOP makes code also less understandable!
a) Is there a solution to this problem? (Can this maybe be solved when I put the whole configuration in an XML File? I dont think so.)
b) Would this problem still exist when I would use AspectJ instead of Spring AOP?
Springs Features using Spring AOP: they dont have this disadvantage?
As Spring AOP is part of many Spring Features (just like declarative Transaction Management or (maybe) Spring Security(?)) I took a closer look at those Features. I was not able to find any disadvantage at all.
c) Lets take the declarative transaction management as an example: managing transactions is so easy with those annotations (#transactional) and I dont really find the disadvantage I mentioned above. I can see the methods that trigger specific behaviour. (all #transactional methods trigger transactional behaviour) Maybe I misunderstood something and this isnt where AOP is used? But if I did not misunderstood this, why is it here possible to see which methods trigger aspects and why isnt it possible to see in my example above? I would really like to know this!
Thank you for answering! :-)
EDIT: a) and b) are answered (use an IDE which marks those methods), c) is still missing :-)
For Point b)
If you use an Eclipse with Spring IDE and AspectJ plugin, or STS, the IDE will show you where Aspects are woven in.
For Point b)
If you use AspectJ and an IDE that supports AspectJ (Eclipse with AspectJ Plugin, or STS), then you will see markers in the souce-code where the Aspect is woven in.
An disadvantaged of Compile time AspectJ is, that you are not able to wove aspects in libraries. (without advanced techniques).
For Point c)
There is only one disadvantage of declarative Aspects like #Transactional. -- You can forget to put the annotation on the method.
But if you have for example a rule like: every public method in a Class annoteted by #Service (or if you like to build you own #TransactionalService), is transactional, then you do not need to specifiy the #Transactional annotation on each method. -- So in Summary: declarative Aspects are very good for reading (you will not overlook them), and they are good if your code is very (lets say) "individual" (instead of the term "not consistent") . But If you work in an Environment with Strong Architecural Rules (like every public method in a #Service class...), then you can Write this rules down in a Point Cut Definition, instead of using declarative Aspects.
Actually for point a) the same answer holds that Ralph gave: use Eclipse with either AspectJ plugin or if you are using Spring anyway, use STS.
That way you will see in your IDE if a certain method matches a pointcut on the left side of your editor, represented by small red arrows:
Actually, Spring AOP supports creating custom annotations.
I defined a annotation named Loggable binding with Advice.The Loggabel could be applied to any method you want.
public #interface Loggable {
}
#Aspect
public class EmployeeAnnotationAspect {
#Before("#annotation(com.ben.seal.spring.aspect.Loggable)")
public void myAdvice(){
System.out.println("Executing myAdvice!!");
}
}