Given the following members of my test class
#Mock
private Gateway gateway;
#Autowired
#InjectMocks
private TransactionManager transactionManager;
#BeforeClass
public void before() {
MockitoAnnotations.initMocks(this);
}
The TransactionManager uses the gateway internally and it is wired up with #Autowired. When I run the tests in this class, they pass. However when I run tests in a separate class that I am expecting to use the concrete implementation of Gateway, they are using the mocked Gateway.
You have to check out the Mockito's subproject for TestNG. You can see an example of usage here in my Mockito Cookbook repo - https://github.com/marcingrzejszczak/mockito-cookbook/blob/master/chapter01/src/test/java/com/blogspot/toomuchcoding/book/chapter1/_3_MockitoAnnotationsTestNg/assertj/MeanTaxFactorCalculatorTestNgTest.java.
To use the listener you have to copy the contents of the https://github.com/mockito/mockito/tree/master/subprojects/testng/src/main/java/org/mockito/testng folder to your project since mockito-testng is not yet released.
I had the same Problem. You can use #DirtiesContext on the test class.
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/annotation/DirtiesContext.html
In this case you don't need any extra packages or code. The context will be reinitialized after your test.
Related
I have two Maven projects A and B, where project B is nested in project A. The structure looks like the following:
Project A:
src/test/java:
MyTest.java
Project B:
src/test/java:
MyNewTest.java
pom.xml
pom.xml
My goal is to let MyNewTest.java act as a wrapper of MyTest.java, and be able to invoke the test methods declared in MyTest.java from MyNewTest.java. MyTest has some injected dependencies.
My question is: how to initialize MyTest in MyNewTest to make sure that all the dependencies of MyTest are injected properly?
MyTest looks like the following:
public class MyTest {
#Autowired
Service service;
#Autowired
TestUtil util;
Info info;
#PostConstruct
void init() {
info = service.getStuff();
}
#Test
public test1() {
service.getMoreStuff();
// more code omitted
}
}
I have tried adding #Component to MyTest, and then in MyNewTest.java, use #Autowired like the following:
public class MyNewTest {
#Autowired
private MyTest baseTest;
#Test
public void runTest() {
// run the test in MyTest.java
baseTest.test1();
}
}
But this doesn't seem to work - baseTest is null. I also tried initializing MyTest by calling its default constructor, but the dependencies failed to be injected as expected. Can anyone suggest a proper way to initialize MyTest.java so that all its dependencies are injected as well? Thanks
The problem with your test is the #Autowired annotations as the Spring wiring isn't being triggered. There are two different paths you can take to fix this.
The first option is to manually instantiate baseTest in MyNewTest at which point it will no longer be null. However, tests will still fail because your two #Autowired dependencies will be null. You can either add setters or inject them via your constructor. Note- these classes should be mocked if you are performing Unit Tests. Here's how it would look if you chose to add these classes via the constructor -
private Service service;
private TestUtil util;
private MyTest baseTest;
#BeforeEach
void setUp() {
service = mock(Service.class);
util = mock(TestUtil.class);
baseTest = new MyTest(service, util);
}
The second option is to add configuration to your Test class to support the Spring wiring. I am not familiar with taking this route as I always choose the first option when possible. There are multiple ways to add the Spring wiring but the easiest is-
#SpringBootTest
#RunWith(SpringRunner.class)
public class MyNewTest {
However, this does not cover all use cases so you may need more specific configurations. You can find some of the possible options here - How to write JUnit test with Spring Autowire?
Edit- As I immediately recognized a problem, I didn't read the rest very carefully and I missed that these were Test classes you were trying to wire together. I am not sure if this is possible.
Only Spring beans can be #Autowired so the first step would be to attempt to add configuration to make your Test class into a Spring bean. I've never heard of this being done before but it would be easy to try. If not, you can get around this problem by using the first option.
The second problem is that tests are not included in the artifact. I'd imagine you could circumvent this issue by mixing your Test classes in with your regular classes but this is considered a bad practice. I've never heard of tests being dependent on other tests but I'd guess this is also a bad practice. What's the reason for wanting to create your Tests this way?
I have read that when using #Mock, it should be used with #RunWith(MockitoJUnitRunner.class), while for #MockBean, it uses with #RunWith(SpringRunner.class).
However, for #Mock, I see that both MockitoJunitRunner or SpringRunner can be used interchangeably. I am rather confused as to why SpringRunner is also working in this situation ?
#RunWith(MockitoJUnitRunner.class) // also work when #RunWith(SpringRunner.class) is used
public class testService {
#InjectMocks
private ServiceA serviceA;
#Mock
private DependencyA dependencyA;
}
to quote this thread when talking about #MockBean
the class is included in the spring-boot-test library. It allows to add Mockito mocks in a Spring ApplicationContext.
Basically #MockBean is the combination of an #Mock and a #InjectMocks. Therefore, you could also use #Mock with springrunner but ofcourse it is not recommended because it is more heavy weight.
Generally you would use Mockito for lightweight unit tests, whereas using #MockBean when you want a mocked servlet environment like in a component test or a hybrid integration test.
Difference between #Mock, #MockBean and Mockito.mock()
typically, if you're using Spring Boot and need to mock a bean from the Spring ApplicationContext you would then use Spring Boot's #MockBean support instead of simply #Mock.
If your bean Injection happening via Autowired annotation, then #mock will not work.
I am testing some service-layer methods on JUnit, but I got NPE error.
Here's my junit code
#Autowired
TeacherServiceImpl teacherServiceImpl;
#Test
public void test(){
String teacherName = "Bernice";
List<Teacher> teachers = new ArrayList<Teacher>();
teachers = teacherServiceImpl.findTeacherByName(teacherName);**(error here)**
}
Here's my service layer code
#Service
public class TeacherServiceImpl implements TeacherService {
#Autowired
private TeacherDao teacherDao;
public List<Teacher> findTeacherByName(String teacherName){
List<Teacher> teachers = new ArrayList<Teacher>();
teachers = teacherDao.findByNameCn(teacherName);
return teachers;
}
}
Any help will be appreciated!
It seems that TeacherServiceImpl is null. Try to use
#Autowired
TeacherService teacherService;
What's more, you should run your Test Case within Spring, that means you should start Spring Framework by adding #Runwith and #SpringBootTest annotation to your test class if you were using Spring Boot.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = TestApplication.class)
public void TeacherServiceTest {
...
}
You should write your tests properly.
Integration testing for the web layer and Unit testing for the service layer.
You are trying to write integration test using #Autowired but I assume that you did not configure it as an integration test. NPE means that teacherServiceImpl reference has no object refer to. #Autowired works only when you have Spring Context with beans that could be injected.
You should not write an integration test for your service, an only Unit test is suitable here (using JUnit + Mockito).
Read please what is Unit testing in general:
What is unit testing and how do you do it?
Unit testing example:
https://howtodoinjava.com/spring-boot2/spring-boot-mockito-junit-example/
Integration testing example:
https://dzone.com/articles/integration-testing-in-spring-boot-1
But I recommend reading more info before coding next time ;)
Man, which class are you testing? if you want to test the TeacherServiceImpl, then you shouldnt mock this, but use constructor (you are testing the mock atm). Second, in your TeacherServiceImpl.class you have a dependency. Unless you mock this dependency and stub the method u use (findByNameCn), you ll be getting NPE
So, in your test, use the constructor for the class you re testing and mock the dependences using Mockito. Dont forget to use the proper annotation for Runner or ExtendWith
I'm assuming that you did not annotate the test class with #SpringBootTest. For this reason you don't have the application context and therefore no injection.
Please read up on testing with Spring :-)
I'm doing some integration tests, on a Spring Boot application.
Usually the integration tests that I was used to develop, was regarding the application domain, without any external service involved.
Since this time I need to make an integration test on a service which uses both a database and an external service called by an SDK, I've tried doing something like the following:
#RunWith(PowerMockRunner::class)
#SpringBootTest
#PowerMockRunnerDelegate(SpringRunner::class)
#PrepareForTest(McpProductService::class)
class MyServiceIntegration {
#Mock
private ExternalService externalService;
#Autowired
#InjectMocks
private MyServiceImpl myService;
#Test
public void thisTestShouldWork() {
...
}
}
What is confusing me is: how should I declare myService attribute? Usually when I use Mockito + PowerMock in my Unit Tests, I usually test the implementation, not the whole Service Interface + Spring Injection. But I can't use #Autowired if I'm using just it's implementation, not the Interface.
Is there any best practice for this issue that I'm facing?
Disclaimer: I'm assuming that what you are after is an end-to-end test of a service interface, backed by multiple classes. I assume (and hope) that you don't have a single class handling both database and webservice integration.
I don't see the need to use PowerMock here, it is usually something one would use for testing legacy code with a lot of static stuff. If you are using Spring boot, your code should be of a quality that makes PowerMock unnecessary.
When writing an end-to-end test, the principles are the same as a per-class unit test, only with a larger scope:
With a unit test, you create an instance of the class under test, and mock all its external dependencies (other classes)
With an end-to-end test, you create an "instance" of your module under test, and mock its external dependencies.
So, here you should find a mechanism to mock the parts of your code that communicates with external sources, like web service clients, database classes (if you don't use an in-memory db for your test (you should)). This will typically be a Spring config that is almost identical to the one used in production, but with said parts mocked out. Then, you just #Inject the parts you need to communicate with in order to complete the test.
Assuming that you use component scan and annotations for all beans, you could mock the endpoint-classes and use profiles:
This code is based on memory only, might not work on copy-paste, but hopefully you could use the concepts..
#Profile("test")
#Configuration
public class TestConfiguration {
#Bean
#Primary
public SomeWebserviceClient someWebserviceClient() {
return mock(SomeWebserviceClient.class);
}
}
Production code:
#Service
public class SomeClass {
#Inject
private SomeWebserviceClient client;
}
Then in the test:
#RunWith(PowerMockRunner::class)
#SpringBootTest
#ActiveProfiles("test")
public class SomeTest {
#Inject
private SomeClass someClass;
#Inject
private SomeWebserviceClient client; //<< will inject mock
}
Mock will also be injected into SomeClass
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.