I'm using Spring 3.1.4.RELEASE and Mockito 1.9.5. In my Spring class I have:
#Value("#{myProps['default.url']}")
private String defaultUrl;
#Value("#{myProps['default.password']}")
private String defaultrPassword;
// ...
From my JUnit test, which I currently have set up like so:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
I would like to mock a value for my "defaultUrl" field. Note that I don't want to mock values for the other fields — I'd like to keep those as they are, only the "defaultUrl" field. Also note that I have no explicit "setter" methods (e.g. setDefaultUrl) in my class and I don't want to create any just for the purposes of testing.
Given this, how can I mock a value for that one field?
You can use the magic of Spring's ReflectionTestUtils.setField in order to avoid making any modifications whatsoever to your code.
The comment from Michał Stochmal provides an example:
use ReflectionTestUtils.setField(bean, "fieldName", "value"); before invoking your bean method during test.
Check out this tutorial for even more information, although you probably won't need it since the method is very easy to use
UPDATE
Since the introduction of Spring 4.2.RC1 it is now possible to set a static field without having to supply an instance of the class. See this part of the documentation and this commit.
It was now the third time I googled myself to this SO post as I always forget how to mock an #Value field. Though the accepted answer is correct, I always need some time to get the "setField" call right, so at least for myself I paste an example snippet here:
Production class:
#Value("#{myProps[‘some.default.url']}")
private String defaultUrl;
Test class:
import org.springframework.test.util.ReflectionTestUtils;
ReflectionTestUtils.setField(instanceUnderTest, "defaultUrl", "http://foo");
// Note: Don't use MyClassUnderTest.class, use the instance you are testing itself
// Note: Don't use the referenced string "#{myProps[‘some.default.url']}",
// but simply the FIELDs name ("defaultUrl")
You can use this magic Spring Test annotation :
#TestPropertySource(properties = { "my.spring.property=20" })
see
org.springframework.test.context.TestPropertySource
For example, this is the test class :
#ContextConfiguration(classes = { MyTestClass.Config.class })
#TestPropertySource(properties = { "my.spring.property=20" })
public class MyTestClass {
public static class Config {
#Bean
MyClass getMyClass() {
return new MyClass ();
}
}
#Resource
private MyClass myClass ;
#Test
public void myTest() {
...
And this is the class with the property :
#Component
public class MyClass {
#Value("${my.spring.property}")
private int mySpringProperty;
...
I'd like to suggest a related solution, which is to pass the #Value-annotated fields as parameters to the constructor, instead of using the ReflectionTestUtils class.
Instead of this:
public class Foo {
#Value("${foo}")
private String foo;
}
and
public class FooTest {
#InjectMocks
private Foo foo;
#Before
public void setUp() {
ReflectionTestUtils.setField(Foo.class, "foo", "foo");
}
#Test
public void testFoo() {
// stuff
}
}
Do this:
public class Foo {
private String foo;
public Foo(#Value("${foo}") String foo) {
this.foo = foo;
}
}
and
public class FooTest {
private Foo foo;
#Before
public void setUp() {
foo = new Foo("foo");
}
#Test
public void testFoo() {
// stuff
}
}
Benefits of this approach: 1) we can instantiate the Foo class without a dependency container (it's just a constructor), and 2) we're not coupling our test to our implementation details (reflection ties us to the field name using a string, which could cause a problem if we change the field name).
You can also mock your property configuration into your test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
#Configuration
public static class MockConfig{
#Bean
public Properties myProps(){
Properties properties = new Properties();
properties.setProperty("default.url", "myUrl");
properties.setProperty("property.value2", "value2");
return properties;
}
}
#Value("#{myProps['default.url']}")
private String defaultUrl;
#Test
public void testValue(){
Assert.assertEquals("myUrl", defaultUrl);
}
}
I used the below code and it worked for me:
#InjectMocks
private ClassABC classABC;
#Before
public void setUp() {
ReflectionTestUtils.setField(classABC, "constantFromConfigFile", 3);
}
Reference: https://www.jeejava.com/mock-an-autowired-value-field-in-spring-with-junit-mockito/
Also note that I have no explicit "setter" methods (e.g. setDefaultUrl) in my class and I don't want to create any just for the purposes of testing.
One way to resolve this is change your class to use Constructor Injection, that can be used for testing and Spring injection. No more reflection :)
So, you can pass any String using the constructor:
class MySpringClass {
private final String defaultUrl;
private final String defaultrPassword;
public MySpringClass (
#Value("#{myProps['default.url']}") String defaultUrl,
#Value("#{myProps['default.password']}") String defaultrPassword) {
this.defaultUrl = defaultUrl;
this.defaultrPassword= defaultrPassword;
}
}
And in your test, just use it:
MySpringClass MySpringClass = new MySpringClass("anyUrl", "anyPassword");
Whenever possible, I set the field visibility as package-protected so it can be accessed from the test class. I document that using Guava's #VisibleForTesting annotation (in case the next guy wonders why it's not private). This way I don't have to rely on the string name of the field and everything stays type-safe.
I know it goes against standard encapsulation practices we were taught in school. But as soon as there is some agreement in the team to go this way, I found it the most pragmatic solution.
Another way is to use #SpringBootTest annotation properties field.
Here we override example.firstProperty property:
#SpringBootTest(properties = { "example.firstProperty=annotation" })
public class SpringBootPropertySourceResolverIntegrationTest {
#Autowired private PropertySourceResolver propertySourceResolver;
#Test
public void shouldSpringBootTestAnnotation_overridePropertyValues() {
String firstProperty = propertySourceResolver.getFirstProperty();
String secondProperty = propertySourceResolver.getSecondProperty();
Assert.assertEquals("annotation", firstProperty);
Assert.assertEquals("defaultSecond", secondProperty);
}
}
As you can see It overrides only one property. Properties not mentioned in #SpringBootTest stay untouched. Therefore, this is a great solution when we need to override only specific properties for the test.
For single property you can write it without braces:
#SpringBootTest(properties = "example.firstProperty=annotation")
Answer from: https://www.baeldung.com/spring-tests-override-properties#springBootTest
I also encourage you to whenever possible pass property as a parameter in constructor like in Dherik answer (https://stackoverflow.com/a/52955459/1673775) as it enables you to mock properties easily in unit tests.
However in integration tests you often don't create objects manually, but:
you use #Autowired
you want to modify property used in a class that is used in your integration test indirectly as it is deep dependency of some directly used class.
then this solution with #SpringBootTest might be helpful.
Related
I use spring boot 2.
I search to test a private method in the facade
#RunWith(SpringRunner.class)
#SpringBootTest
public class SamplingsFacadeTest {
#Autowired
private SamplingsFacade facade;
#MockBean
private SamplingsService samplingsService;
#Test
public void exampleTest() throws Exception {
List<Samplings> samplings = new ArrayList<>();
Samplling sampling = new Samplings();
..
samplings.add(sampling);
//fake call
Mockito.doReturn(samplings).when(samplingsService.getSamplingContainingNonCompliantTest());
//real call
List<FactoryEmailNCDto> factoryEmails = Whitebox.invokeMethod(facade, "prepareDataNoncompliantSampling");
}
public List<Samplings> getSamplingContainingNonCompliantTest() {
return samplingsRepository.findSamplingContainingNonCompliantTest();
}
In Facade In
private List<FactoryEmailNCDto> prepareDataNoncompliantSampling() {
List<FactoryEmailNCDto> factoryEmailNC = new ArrayList<>();
List<Samplings> samplings = samplingsService.getSamplingContainingNonCompliantTest();
for (Samplings sampling : samplings) {
...
}
}
Why when I debug, samplings is null and not the value I created
Mockito.doReturn(samplings)
.when(samplingsService.getSamplingContainingNonCompliantTest());
One potential problem is that doReturn takes the form doReturn(value).when(mock).method(), not doReturn(value).when(mock.method()). The latter is considered an incomplete stubbing. Instead, it should look like this:
Mockito.doReturn(samplings)
.when(samplingsService)
.getSamplingContainingNonCompliantTest();
Note that there may be other problems with your test; the code you've written expects samplingsService to be public and non-final, and your getSamplingContainingNonCompliantTest() to likewise be public, non-static, and non-final, but the code sample you have does not confirm that. You may want to call Mockito.validateMockitoUsage() in an #After method, or use a #Rule that handles Mockito annotations and cleanup for you.
I have created spring-boot project which bases on Groovy instead of Java.
Now I have following #RestController:
#RestController
class HelloRest {
private final HelloService helloService
#GetMapping("hello")
String hello(#RequestParam("name") String name) {
helloService.createHelloMessage(name)
}
}
Question is how to inject
#Service
class HelloService {...}
in most simple way avoiding boilerplate (in this case the constructor) code?
In Java I would use: #lombok.RequiredArgsConstructor and in fact it works also if I use it in my groovy project.
On the other hand for example the #Immutable annotation from groovy.transform doesn't work as it creates in fact more than single constructor. Whereas Spring expects single constructor to be able automatically #Autowired the dependencies.
As far I see 2 solutions:
Generate the constructor
Use lombok with its annotations
Is there any solution build into Groovy which could be used here instead?
At this moment there is no Groovy mechanism that does same thing as #lombok.RequiredArgsConstructor. The main problem in your case is that Groovy always generates no-args default constructor for all currently known features like #Immutable annotation. The closest (but not accurate) way is to use #TupleConstructor like:
#RestController
#TupleConstructor(includes = ['helloService'], includeFields = true, includeProperties = false, force = true)
class HelloRest {
private final HelloService helloService
#GetMapping("hello")
String hello(#RequestParam("name") String name) {
return helloService.createHelloMessage(name)
}
}
This Groovy code will produce bytecode similar to this Java code:
#RestController
#TupleConstructor(
includeFields = true,
force = true,
includeProperties = false,
includes = {"helloService"}
)
public class HelloRest implements GroovyObject {
private final HelloService helloService;
public HelloRest(HelloService helloService) {
CallSite[] var2 = $getCallSiteArray();
MetaClass var3 = this.$getStaticMetaClass();
this.metaClass = var3;
this.helloService = (HelloService)ScriptBytecodeAdapter.castToType(helloService, HelloService.class);
}
public HelloRest() {
CallSite[] var1 = $getCallSiteArray();
this((HelloService)null);
}
#GetMapping({"hello"})
public String hello(#RequestParam("name") String name) {
CallSite[] var2 = $getCallSiteArray();
return (String)ShortTypeHandling.castToString(var2[0].call(this.helloService, name));
}
}
It is almost what you need, except this default constructor that was generated as well.
Things are getting even more complicated when using #Immutable annotation, because this version would generate 3 constructors:
public HelloRest(HelloService helloService)
public HelloRest()
public HelloRest(HashMap args)
Of course in this case you would have to remove private final in front of HelloService field definition, because this AST transformation works only with fields that are not yet final.
In this case two options you have found (creating construct manually or using Lombok) are probably the best solutions to your problem.
Alternative solution
There is also one "dirty" solution that allows you to write less amount of code, but promotes injection by reflection. Consider following code:
#RestController
class HelloRest {
#Autowired
private final HelloService helloService
#GetMapping("hello")
String hello(#RequestParam("name") String name) {
return helloService.createHelloMessage(name)
}
}
It will generate bytecode similar to following Java code:
#RestController
public class HelloRest implements GroovyObject {
#Autowired
private final HelloService helloService;
public HelloRest() {
CallSite[] var1 = $getCallSiteArray();
MetaClass var2 = this.$getStaticMetaClass();
this.metaClass = var2;
}
#GetMapping({"hello"})
public String hello(#RequestParam("name") String name) {
CallSite[] var2 = $getCallSiteArray();
return (String)ShortTypeHandling.castToString(var2[0].call(this.helloService, name));
}
}
Even though there is only single default constructor that does not even touch our helloService field, Spring bean will get injected by reflection. I share this option only to show all alternatives, although your initial instinct to use constructor injection is the best possible way to use dependency injection in practice.
You can use #Cannonical or #Immutable on the class. That way the constructor will be created for you
JUnit's #BeforeClass annotation must be declared static if you want it to run once before all the #Test methods. However, this cannot be used with dependency injection.
I want to clean up a database that I #Autowire with Spring Boot, once before I run my JUnit tests. I cannot #Autowire static fields so I need to think of a work around. Any ideas?
Just use #Before (instead of #BeforeClass) (or Spring's #BeforeTransaction (depending on how you initialize the database)). This annotation must been attached to an nonstatic public method.
Of course: #Before run before EACH test case method (not like #BeforeClass that runs only once.) But if you want to run it exactly once, then use an static marker field.
private static boolean initialized = false;
...
#Before
public void initializeDB() {
if (!initialized) {
... //your db initialization
initialized = true;
}
}
---
For JUnit5: Test Execution Order and #TestInstance(Lifecycle.PER_CLASS)
Kotlin example:
#ExtendWith(SpringExtension::class)
#TestInstance(PER_CLASS)
class BeforeInstanceTests {
private var initialized: String = ""
private val callList: MutableList<String> = ArrayList()
#BeforeAll
fun beforeAllNonStatic() {
initialized = "initialized"
assertEquals(0, callList.size)
}
#Test
fun test1() {
assertEquals("initialized", initialized)
callList.add("test1")
}
#Test
fun test2() {
assertEquals("initialized", initialized)
callList.add("test2")
}
#Test
fun test3() {
assertEquals("initialized", initialized)
callList.add("test3")
}
#AfterAll
fun afterAllNonStatic() {
assertEquals("initialized", initialized)
assertEquals(3, callList.size)
assertTrue(callList.contains("test1"))
assertTrue(callList.contains("test2"))
assertTrue(callList.contains("test3"))
callList.clear()
initialized = ""
}
}
Have a look at the DBUnit library - it's designed to perform the actions you're describing. It can create & tear down database instances and provides you with simple ways to do this.
Though accepted answer is clever, seems hacky. Have you tried using a normal Constructor?
public class MyJUnitTest {
public MyJUnitTest() {
// code for initializeDB
}
// Tests
}
Try this solution:
https://stackoverflow.com/a/46274919/907576 :
with #BeforeAllMethods/#AfterAllMethods annotations you could execute any method in Test class in an instance context, where all injected values are available.
I would like to use both #Post and #Get on the same method like
#GET
#POST
#Path("{mode}")
public void paymentFinish(#PathParam("mode") String mode, String s) {
logger.debug("Enter PayStatus POST");
logger.debug(mode);
}
Even I write like this, I got error. What I want is whatever get or post to the sameurl, the same method works. Is it possible? Now I separate two methods, one for get and one for post.
Unfortunately, only one should be used in order to avoid Jersey exception.
But you could do something like :
#GET
#Path("{mode}")
public void paymentFinish(#PathParam("mode") String mode, String s) {
commonFunction(mode);
}
#POST
#Path("{mode}")
public void paymentFinishPOST(#PathParam("mode") String mode, String s) {
commonFunction(mode);
}
private void commonFunction(String mode)
{
logger.debug("Enter PayStatus POST");
logger.debug(mode);
}
By doing so, if you want to change inner behavior of your functions, you will only have to change one function.
Note that method name in java for get vs post need to be different.
After searching a lot trying to avoid the solution above, I found nothing....
Then I decided to create a custom annotation so I didn't have to waste time duplicating methods.
Here's the github link: Jersey-Gest
It allows you to create GET and Post Methods on a single Annotation by generating a new class from it.
I hope it helps you the same way it helped me :)
Edit:
If for some reason the above link stops working, here's what I did:
Created a compile-time annotation #RestMethod for class methods.
Created a compile-time annotation #RestClass for classes.
Create an AnnotationProcessor which generates a new class with Jersey's corresponding annotations and for each method creates a GET and a POST method which callsback to the original method annotated with #RestClass.
All methods annotated with #RestMethod must be static and contained within a class annotated with #RestClass.
Example (TestService.java):
#RestClass(path = "/wsdl")
public class TestService
{
#RestMethod(path = "/helloGest")
public static String helloGest()
{
return "Hello Gest!";
}
}
Generates something like (TestServiceImpl.java):
#Path("/wsdl")
#Produces("application/xml")
public class TestServiceImpl
{
#GET
#Path("/helloGest")
#Produces(MediaType.APPLICATION_XML)
public String helloGestGet()
{
return TestService.helloGest();
}
#POST
#Path("/helloGest")
#Consumes(MediaType.WILDCARD)
#Produces(MediaType.APPLICATION_XML)
public String helloGestPost()
{
return TestService.helloGest();
}
}
With this class
#Component
public class Sample {
#Value("${my.name}")
public static String name;
}
If I try Sample.name, it is always 'null'. So I tried this.
public class Sample {
public static String name;
#PostConstruct
public void init(){
name = privateName;
}
#Value("${my.name}")
private String privateName;
public String getPrivateName() {
return privateName;
}
public void setPrivateName(String privateName) {
this.privateName = privateName;
}
}
This code works. Sample.name is set properly. Is this good way or not? If not, is there something more good way? And how to do it?
First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.
Your workaround is valid, you don't even need getter/setter, private field is enough. On the other hand try this:
#Value("${my.name}")
public void setPrivateName(String privateName) {
Sample.name = privateName;
}
(works with #Autowired/#Resource). But to give you some constructive advice: Create a second class with private field and getter instead of public static field.
Soruce of this info is this: https://www.baeldung.com/spring-inject-static-field
Spring uses dependency injection to populate the specific value when it finds the #Value annotation. However, instead of handing the value to the instance variable, it's handed to the implicit setter instead. This setter then handles the population of our NAME_STATIC value.
#RestController
//or if you want to declare some specific use of the properties file then use
//#Configuration
//#PropertySource({"classpath:application-${youeEnvironment}.properties"})
public class PropertyController {
#Value("${name}")//not necessary
private String name;//not necessary
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
This is my sample code for load static variable
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class OnelinkConfig {
public static int MODULE_CODE;
public static int DEFAULT_PAGE;
public static int DEFAULT_SIZE;
#Autowired
public void loadOnelinkConfig(#Value("${onelink.config.exception.module.code}") int code,
#Value("${onelink.config.default.page}") int page, #Value("${onelink.config.default.size}") int size) {
MODULE_CODE = code;
DEFAULT_PAGE = page;
DEFAULT_SIZE = size;
}
}
For those who want to use ApplicationContext in the main class of a Spring Boot application, you can just use the return value of SpringApplication.run.
Although workarounds may need to be implemented, one should try to avoid them in most scenarios if possible. Spring is great at handling dependency injection and treats most objects as Singletons. This means that Spring can handle the creation of objects for you, and the injection of these objects at runtime. When combining this with the fact that your Spring managed bean is likely a Singleton, the use of static methods and variables is largely unnecessary. You can simply autowire in an instance of the object you are looking for at the constructor level or variable level and reference the non-static version of the method or variable. This is ideal and behaves similarly to a static reference. Non static variables are basically static because you are only ever using one instance of the object in every part of the code and because of dependency injection you are never handling the instantiation of the object, just like with a static reference! Great! Now I'm sure there are instances where you need the work around (i.e. you aren't using dependency injection or class is not a singleton), but try to not use workarounds if possible. Also this is just my 2 cents. Someone may be able to offer 3. (:
public class InjectableClass{
#Value("${my.value}")
private String myString;
public String nonStaticMethod(){
return myString;
}
}
public class LogicClass{
private InjectableClass injectableClass;
#Autowire
public LogicClass(InjectableClass injectableClass){
this.injectableClass = injectableClass;
}
public void logicClassMethod(){
System.out.println("Hey! Here is the value I set on myString: " +
injectableClass.nonStaticMethod() + ". That was
basically like using a static method!");
}
}