I am new to spring concepts. I am trying to write a Junit for one of the class's method. I want to mock spring framework JdbcTemplate class that is being used as #Autowired from multiple location. But I don't want to use #Mock in each class. Is there any way I can mock this class and that can be used from multiple location by using #Autowired.
Thanks in Advance.
Define a spring profile specific for your tests (as example "test"), in that profile create the JdbcTemplate bean with a mock library and with the annotation #Profile("test"). In that way this mock will be created only when the "test" profile is active.
Add the annotation #Profile("!test") to the real JdbcTemplate bean so it will not be created in the test profile.
Then add the #ActiveProfiles("test") annotation on top of you test class.
Kind of a non-answer, but I would not recommend using Spring to inject dependencies when unit testing. If you are using constructor injection, then you can simply call the constructor from the unit test and pass in your mock or test double manually. This makes it very clear and explicit from the unit test what the supplied dependency is for the purposes of the test. If you are using setter injection, you can do the same. Don't materialize the class under test via Spring, just construct the class under test from your junit test class, and supply the dependencies you want on that class imperatively.
Related
I am working on a Spring MVC project where I am dealing with different types of services,Repositories i.e classes annotated with #Service and #Repository. I am confused with a couple of questions:
When to use #AutoWired annotation?
I have seen various repositories using this:
CourseRepository crepo=new CourseRepository();
and I have seen this also
#AutoWired
private CourseRepository crepo;
Which one of the above options should be used to get an instance of
repository in Service class?
Can I use #AutoWired for classes which are not annotated with #Repository or
#Service?
I am a beginner in this java world.Any help will be highly appreciated.
Thanks
You use new for data objects, which in most modern architectures are passive (they're not "active records"). Everything else is a service object, and you should inject those. (The one place that you do use new is with an #Bean method, which is a "factory" that creates the service object; in this case you normally pass the dependencies as method parameters.)
Note that it is recommended to use constructor injection instead of field injection; it makes your code easier to test, and it eliminates the possibility of certain kinds of errors. In fact, if using constructor injection, it's not required to have any Spring annotations in your service classes at all; beans can be registered using #Import instructions or #Bean methods on a configuration class.
You should #Autowire the dependencies instead of instantiating it yourself. Doing so, service and repo layer will be loosely coupled. Moreover, a mock repository can be easily injected in service's JUnit test class if dependency is autowired. To conclude, use below:
#Autowired
private CourseRepository crepo;
A class not annotated with any of below stereotype annotations will not be in Spring's IoC (Inversion of Control) container. Hence, no point in autowiring in a class that is not annotated with any of below annotations.
#Component, #Controller, #Service, #Repository
Dependency injection means that the framework is the one who handles the classes instantiation and the object of that class is going to be injected (thanks to #Autowired annotation) in the class where you need it. In other words, you do not need to instantiate service and repository classes by yourself using new operator, you just need to tell the framework that those classes need to be injected and that's why you use #Autowired annotation.
I am writing unit tests for my services in Spring, Java. I mock all dependencies in a tested class and I instantiate the tested class in a constructor, to which I pass mocked classes. The problem is that the tested class injects properties from .properties file into fields that are inside it (let's say Strings).
I use the standard combination of #PropertySource on a class level and #Value on a field level inside my tested class.
As we know, properties injection fails when class is instantiated through constructor (not as a bean during the Spring Container initialization). How do you deal with such problem?
I've got one solution, though I think it is bad and unsatisfactory, that is:
1. to #Autowire the class under test normally, then replace all its dependencies by using a setter.
I also know about the #TestPropertySource annotation and if I understand correctly, it does not provide a solution and it is only a way to override already existent properties - which is not the case, as we cannot really use any properties.
Thanks for help in advance :)
It is rather straight : in your unit test, inject the property in a String field and create the object under test not in the constructor of the test class but in the hook method invoked after the container has loaded the Spring context.
In JUnit 4, you specify this hook method with #Before and in JUnit 5 with #BeforeEach.
It would give something like :
#RunWith(SpringJUnit4ClassRunner.class)
public class FooTest{
Foo foo;
#Value("${myProp}")
String myProp;
#BeforeEach
public void beforeEach(){
foo = new Foo(myProp);
}
}
Note that to make your test be executed faster you should load from the Spring context only what your test requires : the environment part.
I am developing a REST API with Spring Boot.The problem it's that I have one interface and two implementations and I want to test only with the mock implementation.
Interface CRMService
#Service
CRMServiceImpl
#Service
CRMServiceMock
Implementations: the first one is the real integration with the backend and the second is a mock for testing purposes, what's the best approach? Integration test or test based on the active profile ? If I need to autowire a service based on profile what's the best practice?
While I'm sure there's exceptions, generally it shouldn't be integration or unit tests (often involves mocks), but both; see testing pyramid concept.
Integration tests: just use the real service. If it calls out to other live services, then consider injecting the URLs as Spring Boot properties which point to mock servers in the test environment (Node.js or something easy and quick).
Unit tests: Consider using a test-framework like Mockito. Using this you can write your tests with mocks approximately like so:
private CRMServiceImpl mockService = mock(CRMServiceImpl.class);
#Test
public void someTest() {
when(mockService.someMethod(any(String.class), eq(5))).thenReturn("Hello from mock object.")
}
The above example roughly translates to "when some class invokes 'someMethod(String, int)' on your service, return the String specified".
This way allows you to still use mocks where necessary, but avoids having to maintain entire mock implementation profiles and avoids the problem of what to auto-wire.
Finally, if you need a full separate implementation, consider not auto-wiring services! Instead, use #Bean annotations in your configuration class and inject it via constructors into the classes that need it. Something like so:
#Configuration
public class ApplicationConfiguration {
#Value{$"service.crm.inmem"} // Injected property
private boolean inMem;
#Bean
CRMService getCRMService() {
if (inMem) {
return new CRMServiceMock();
}
return new CRMServiceImpl();
}
#Bean
OtherService getOtherService() {
// Inject CRMService interface into constructor instead of auto-wiring in OtherService.class
return new OtherService(getCRMService());
}
}
An example of when you could use ^^ would be if you wanted to switch between an in-memory store, and a real database-connection layer.
Personally I'd suggest doing dependency injection like the above example even when there aren't multiple implementations since as a project grows, if an auto-wired property fails it can be difficult to track down exactly why. Additionally explicitly showing where dependencies come from can help with organizing your application and visualizing your application hierarchy.
For some integration tests, we use Spring’s #ContextConfiguration to create a real Spring context during the test. Now, it’s not supposed to be a full integration test, so we need a whole bunch of the Spring beans as mocks. This is not too complicated using Mockito and Spring’s factory-method, and even easier with Springockito.
But, this is using Mockito, while we are just migrating to JMockit. I would much prefer to use JMockit here as well. Basically, I am looking for a replacement for Springockito that uses JMockit instead.
I can also do it by hand. However, Mockito and JMockit seem to differ in one very important way: While in Mockito, you create mocks imperatively using a call to a method, in JMockit you get mocks declaratively ‘injected’ into your test. That’s too late to populate the Spring context. So if anyone can answer that, I’m happy as well: How can you create a mock in JMockit in your code?
If you are using Spring Test to do all the injection, then you can just let it do the job of creating instances for all dependencies, while having them mocked through suitable mock fields/parameters declared with the #Mocked or #Capturing annotations. The latter one will mock any implementation class that Spring has chosen to instantiate, even though the type used in the mock declaration is an interface or base class.
Alternatively, you could just let JMockit itself resolve all dependencies, by using #Tested(fullyInitialized = true) for top-level tested objects, with mocked dependencies provided as #Injectable's.
A "dirty" trick we use with Spring and Integration Tests while we still need to mock something, is to replace - where required - the real configuration, e.g.
#Configuration
#Profile("!test")
public class MyConfig {
#Bean
public MyBean bean() {
/** Real bean **/
}
}
with a mock one
#Configuration
#Profile("test")
public class MyTestConfig {
#Bean
public MyBean bean() {
final MyBean bean = mock(MyBean.class);
when(bean.doSomething()).thenReturn(withReply());
return bean;
}
}
it works with a "real" Spring Integration Test context and Mockito, it should work with JMockit as well, as long as you are able to create your bean with JMockit version of your class: basically something equivalent to mock(MyBean.class).
Edit: Whilst I am not familiar with JMockit, it seems that an equivalent way could be
#Configuration
#Profile("test")
public class MyTestConfig {
#Injectable MyBean mockXyz;
#Bean
public MyBean bean() {
/** You can probably mock its behaviour **/
return mockXyz;
}
}
I have a question about the usage of SpringJUnit4ClassRunner. For pure Junits or Unit Test cases should we use Spring based annotations such as #Autowired along with SpringJUnit4ClassRunner or should we use only the MockitoJUnitRunner instead with the #RunWith annotation at the top of the Test class?
I mean replacing
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-applicationContext.xml" })
with just
#RunWith(MockitoJUnitRunner.class)
at the top of the class. It works for me.
In Junits we normally do not make any external calls such as calls to DB or call to some other web service. We have to mock these external calls using #Mock annotations on this service objects. And then create a real object of the class that we are testing and that depends on these mocks. We can then use #InjectMocks on the real object so that it will be injected with the mocked objects.
Example Service-A->Calls->Service-B->Calls->Service-C
While testing A we should mock Service B & while testing Service-B we should mock Service-C.
Some code Snippet
#RunWith(MockitoJUnitRunner.class)
public class TestServiceA {
#Mock
B mockObj;
#InjectMocks
A realObj;
#Test
public void testServiceA() {
.....
.....
}
}
So, I feel for Unit test cases we need not rely on Spring container to provide us the instance of the class we are testing.
Please give your suggestions.
Using SpringJUnit4ClassRunner.class instead of MockitoJUnitRunner.class
If you try to simply unit test a class without the dependencies, like you describe, there is no need for the SpringJUnit4ClassRunner. This runner is able to generate a complete Spring context with (mock) objects you can define in your (test) application context configuration. With this mechanism the SpringJUnit4ClassRunner is much slower than the regular MockitoJUnitRunner.
The SpringJUnit4ClassRunner is very powerful for integration test purposes.
I default start with the MockitoJUnitRunner and if I reach the limits of this runner, for instance because I need to mock constructors, static methods or private variables, I switch to PowerMockJUnitRunner. This is for me a last resort as it normally tells the code is ‘bad’ and not written to be tested. Other runners are normally not necessary for isolated unit tests.
Building on Sven's answer, Let us say that you needed to test an assembly of classes while mocking out bits that go to the database, or call an external service, you would look to run the test with SpringJUnit4ClassRunner.
If you were trying to test a Single Java Class as a Unit, mocking out both the integration bits and local collaborators, then running the test with MockitoJUnitRunner is sufficient and faster as well.