I wonder whether it is possible to have a fixture that can be shared between testcases, for instance a hibernate session.
You want all your tests (not testcases) to share the same hibernate session ?
Create it in your setUp() method, only if it has not been already created, and store it in a static member of your testcase class, similar to a singleton implementation.
Related
we are in situation where we cannot simple rollback data after test, so we decide to use Flyway java API like this:
#Autowired
protected Flyway flyway;
#AfterEach
public void restoreDatabase() {
flyway.clean();
flyway.migrate();
}
Is possible execute clean and migrate after each test class instead of test method? I need call this in #AfterAll annotated static method, but this type of methods have to be static so I cannot use autowired component Flyway. Can you advice me any workaround? Thank you.
The following solution may help you.
Besides the #Rollback annotation there is also the possibility to mark a class (or method) as "dirty" with the annotation org.springframework.test.annotation.DirtiesContext. This will provide the test cases a fresh context. From the Java Docs:
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.
#DirtiesContext may be used as a class-level and method-level annotation within the same class or class hierarchy. In such scenarios, the ApplicationContext will be marked as dirty before or after any such annotated method as well as before or after the current test class, depending on the configured methodMode and classMode.
Let me show you an example:
#RunWith(SpringRunner.class)
#SpringBootTest
#DirtiesContext(classMode = ClassMode.BEFORE_CLASS)
public class SomeTestClass {
#Autowired
private ExampleController controller;
#Test
public void testSomething() {
//Do some testing here
}
Now in this case, with an embedded DB (like H2), a fresh DB will be started containing no changes from previous transactions.
Please note that this will most probably slow down your test cases because creating a new context can be time consuming.
Edit:
If you watch the log output you'll see that Spring creates a new application context with everything included. So, when using an embedded DB for the test cases, Spring will drop the current DB and creates a new one and runs all specified migrations to it. It's like restarting the server which also creates a new embedded DB.
A new DB doesn't contain any commits from previous actions. That's why it works. It's actually not hacky imo but a proper set up for integration tests as integration tests mess up the DB and need the same clean setup. However, there are most probably other solutions as well because creating new contexts for every test class may slow down the execution time. So, I would recommend to annotate only classes (or methods) which really needs it. On the other hand, unit tests are in most cases not very time critical and with newer Spring versions lazy loading will speed up startup time.
I have a custom object which I like to share between different Spring-Boot components (e.g. WebHandler, Authenticator, Filter).
Maybe the easiest way is a static object in the main-class but thats not very elegant.
Whats the most common way to do it?
The whole point of spring as a container is to manage your objects.
Now statics do not have a well defined lifecycle ( when exactly this object gets created, who disposes it when the application gets closed, etc)
Speing answers all these questions by using thecdependency injection techniques. If you're already using spring then you should define this 'shared object' as a spring bean (by default it will have scope singleton just like static object that you've proposed but managed by spring container which is better - it will manage the lifecycle of the object by itself)
Then given the classes that must be dependent of the object are beans by themselves you can inject that bean:
class MySharedObject {}
class MyWebHandler implementsWebHandler {
private final MySharedObject mySharedObject;
public MyWebHandler(MySharedObject mySharedObject) {
this.mySharedObject = mySharedObject;
In addition to the lifecycle management this way allows easy unit testing of classes that use the shared object (like 'MyWebHandler' in this case) - now uou can create a stub/mock of the shared object and pass it into the handler - something that cannot really be easily done when using statics
So in summary if you can use spring and define it as a bean - by all means do so, the usage of statics is discouraged if you already have a dependency injection container
If you have shared object first of all it should not contain any state as differents components can change it and also it should be thread safe.
It is fine to reuse it across all components via #Autowired annotation but you need to be sure that it is threadsafe. Spring bean scope singleton is not thread safe out of box it dependes how you write the code.
You can use as static method but it dependes on logic which you have and if those component has an dependency on another objects and if they need to in spring IOC.
I am mocking a repository with the annotation #mock and then saving some data to the repository in the test class. Is the data really getting stored in the repository?
In another class when the same data is fetched it is showing not found. How will I test my class if the data is not stored in the repository?
Most likely, when you use the #Mock annotation correctly in your test code, your mocking framework will come and instantiate something for you under that name:
#Mock
WhatEver someWhatEver;
In other words: when the above "executes", someWhatEver will reference some object that conforms to the "API" that the WhatEver class provides.
Meaning: you can call all methods that exist on that class. And nothing will happen. Because someWhatEver isn't a instance of your real production class. It is something that looks like it.
Thus, the real answer is: you step back, and you research the whole topic. There is no point in doing "unit testing" using some mocking framework without "understanding" what you are doing. The tutorial by vogella is a good starting point.
Mocking is a way to encapsulate your unit tests. If you want to test a service method you are not interested if the repository is working. For this you will write repository tests. Therefore you mock the repository call and tell which result should be returned to test your method in all possible situation. The mock itself is a proxy, therefore there the data which are you saved are not really safed in your database. This has the advantage that you haven´t to start your whole context and the tests are much faster.
When we want to do a Service Unit Test in SpringBoot Application We have not gone use Real DataBase just we need to Mock DataBases.
Similarly When u want to do Unit Test any External Serivce in Your class Just U can Mock that External Service call.
A Mockito mock allows us to stub a method call. That means we can stub a method to return a specific object. For example, we can mock a Spring Data JPA repository in a service class to stub a getBooks() method of the repository to return a Book object.
I have created a couple unittest classes in the same package. All these classes have exactly one testcase and have the same annotation as shown below:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes= {TestConfig.class} )
When I run these testcases, I want each testcase be run in its own application context. But it seems all the testcases in the same package share one single application context, be it run from maven command line, or in Eclipse select the package to run as junit.
If I duplicate the TestConfig wiht names like TestConfig1, TestConfig2, etc. and annotate different test class with different TestConfig class, then each test will run in its own context instance.
Is there other elegant method to achieve this?
Thanks a lot.
This is the default behavior of Spring test. Spring test default caches the application context across the tests. This decreases the test execution time.
I dont know about your use case. If u have any where u are dirtying the application context(changing the state of the beans that are managed by springs that is affecting the subsequent tests ) then u can go for annotating the test method with #DirtiesContext. Spring test reloads the context for these methods. See below link how to use DirtiesContext.
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/integration-testing.html#testcontext-ctx-management-caching
Use this feature carefully whenever needed only as this may shoot up your test execution time exponentialy.
I have a Spring Boot project for which one of the developers has written Integration tests against an in-memory DB. Here is some background before I put my question :
We have following Maven modules :
1) web-persistence : which store all entities and interfaces and corresponding implementations. All these classes are in package com.mycompany.persistence.
2) web-services : which stores all our rest controllers and spring security related classes. These are all in package com.mycompany.services
3) web-services module has maven module dependency on web-persistence module.
4) In web-services module we have defined a service UserContextServiceImpl which is implementation of interface IUserContextService. This service basically encapsulates Spring's SecurityContextHolder functionality by exposing only those parts of a current user related information which is needed through its methods so that everywhere we don't have to use SecurityContextHolder. The implementation class is annotated with #Service("userContextService").
5) Interface IUserContextService is in persistence module. There is another class AppDependecyHeper in persistence module which implements ApplicationContextAware and returns UserContextService's concrete instance by calling appContext.getBean('userContextService') where appContext is holding ApplicationContext when application is initialized.
6) Now we don't want to expose Spring Security classes in persistence module(for reasons which are out of context here) and hence above arrangement of getting current user information through a service by calling getBean() method of applicationContext in persistence layer class AppDependencyHelper. This information is then used to update audit fields createdBy and modifiedBy using an EntityListener.
7) Actual application uses only single ApplicationContext where both persistence layer classes and web controllers are loaded in one single spring context.
8) Everything works fine when application runs. However when our integration test Runs the call appContext.getBean('userContextService') fails and throws NosuchBeanDefinitionException as it is unable to find the bean with name 'userContextService'
9) Now finally the code of our integration Test (only giving relevant details) which is located in com.mycompany.persistence.embeddeddb package:
#Runwith(SpringJUnit4ClassRunner.class)
#ConfigurationContext
class MyEntityTest{
#Configuration
#ComponentScan("com.mycompany.persistence")
public static class Config{
.....
}
.....//code which eventually gives call to
AppDependencyHelper's method which in turn tries to retrieve userContextService Bean.
}
Now the questions :
1) Why it fails to retrieve the bean? I have tried addingcom.mycompany.services like below
#ComponentScan({"com.mycompany.persistence","com.mycompany.services"})
but to no avail.
2) What I am able to understand by reading whatever I got is that #ContextConfiguration needs to be provided with either XML files or Annotated classes or WebApplicationInitializers(in my case as we are having only single ApplicationContext) to create an ApplicationContext from #Configuration classes. However I cannot do that as maven starts complaining about circular dependency which is rightly so as my #Service annotated class UserContextServiceImpl is in web-services module which is dependent on web-persistence module already where the test case class is written.
3) The only solution I can think of is moving all integrations test classes to web-services module so that I can tell #ConfigurationContext all the classes from which it should create an ApplicationContext.Am I right?
Last point : The ApplicationContext class is of type GenericApplciationContext when I run tests. When I run application its obviously AnnotatedEmbeddedWebApplicationContext
please let me know if there is any solution to this problem?
From what I'm guessing you are trying to use a component from your web-service module in your integration tests. If that's the case, than yes, you should move your integration test cases to your web-service module - as you've already suggested in your question.
EDIT: You should really rethink your design, because you have a circular dependency problem here: Your web-service module depends on web-persistence, but the implementation of your IUserContextService in web-persistence is found in web-service.
You should probably move your IUserContextService (and all your integration tests) to your web-service package.