I am doing some tests for the class Export
I need to mock a method so I made a mockito (I am new to Mockito)
public Class ExportServiceImpl implements ExportService{
#Autowired
Service service
public void export(){
String exportString = service.getPath();
domoreStuff() ....
}
And
public Class ServiceImpl implements Service(){
public String getPath(){
return "thePath";
}
}
I need to mock the getPath() method so I did in the TestNG
public class ExportTestNG(){
public textExport(){
Service serviceMock = Mockito.mock(Service.class);
Mockito.when(serviceMock.getData()).thenReturn("theNewPath");
System.out.println("serviceMock.getData() : " + serviceMock.getData()); // prints "theNewPath", OK
exportService.export(); // the getData() is not the mockito one
}
}
I may have not correclt mockito and I may not have understood how it works.
Any idea ?
You can use Mockito to inject the mocks for you and avoid having to add setter methods.
#RunWith(MockitoJUnitRunner.class)
public class ExportTestNG(){
#InjectMocks
private ExportServiceImpl exportService;
#Mock
private Service serviceMock;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
public textExport(){
Mockito.when(serviceMock.getData()).thenReturn("theNewPath");
exportService.export();
}
}
You need to wire the mock service into the exportService object.
If you have a setter for the service member variable then do this:
exportService.setService(serviceMock);// add this line.
exportService.export();
If you don't have a setter you will need to perform the wiring before calling export.
Options for this include:
Set the value of the service member variable using reflection.
Write a test-only version of the Service and use a test-only version of the spring configuration xml files.
Something else (that I have never done and thus don't know about).
Related
I have a singleton class (so private constructor) which needs to use a Spring Data repository during initialization. I have one injected as a constructor argument. Roughly:
#Controller
public class MyClass {
#Autowired
private MyClass(MyRepository repo) {
repo.findAll();
}
}
I want to unit test my class, so I need to have a mock repository initialized with mock values and then passed into my class before my class is initialized. How do I write my Mockito mocks in my JUnit test to make this possible?
You don't need Spring; this is an advantage of constructor injection. Just use MyRepository mockRepo = mock(MyRepository.class) and new MyClass(mockRepo).
(Your constructor should be public, by the way. You seem to be making the common mistake of confusing different senses of "singleton"; in the case of DI it simply means that the container only makes a single instance and shares it. Finally, if you only have one constructor you don't need #Autowired.)
Unit test should be independent. It means, we are not using real data from database even call any service from our test file.
Assuming you are using JUni5 and have findAllStudents() in your controller. So your test file approximately like this
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MyClassTest {
#Mock
private MyRepository repo;
#InjectMocks
private MyClass controller;
#BeforeAll
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testDataIsExist() {
List<String> expectednames = new ArrayList();
expectedNames.add("Foo");
expectedNames.add("Bar");
Mockito.when(myRepo.findAll()).thenReturn(expectedNames);
List<String> result = controller.findAllStudents();
Assertions.assertNotNull(result);
Assertions.assertEquals(expectednames, result);
}
}
So we are mock all the services we use in controller, then inject to controller itself. Then inside the test method we mock repo.findAll() to return expectedNames so if the controller find that function it will return what mock says to return.
After we call the function, we have to make it sure that the result is according to what we expected.
There is little value in a "unit test" for a #Controller implementation. If you use #WebMvcTest, then you can use #MockBean:
#WebMvcTest
class MyControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private MyRepository repository;
#Test
void testSomething() {
mockMvc.perform( ... );
}
}
I have a service class that extends another service with a constructor. This class has an autowired field and a method that I wanted to unit test using Mockito. However, I am having trouble writing a unit for it.
Let say the service looks somewhat like this:
#Service
public class SomeService extends Service {
#Autowired
private SomeClient someClient;
public SomeService(Product product, #Qualifier(Constants.SOME_BEAN) Details temp) {
super(product, temp);
}
#Override
public State create() {
Request request = new Request();
request.set...
request.set..
Status status = someClient.createTenant(request);
..
.. // construct a State object and return
}
}
Now, I am writing a test for this class and I am trying to unit test the method create() above. I am having trouble mocking someClient there when this method is called by my test.
The test class looks somewhat like:
#RunWith(MockitoJUnitRunner.class)
public class SomeServiceTest {
private Detail temp;
private SomeFacade service;
private SomeClient someClient;
private Product product;
#Before
public void setup() {
temp = mock(Details.class);
product = mock(Product.class);
service = spy(new SomeService(product, temp));
someClient = mock(SomeClient.class);
}
#Test
public void test() {
Status status = new Status();
status.setStatus(...);
when(someClient.createTenant(any())).thenReturn(status);
State state = service.create();
// asserts
}
}
What I want to is that when I call service.create in the test above, the call
someClient.createTenant(request); in the method tested should be mocked to return a value and this is something I am not able to get working. Any help?
We can use Mockito's #InjectMocks-annotation to inject mocks into our unit under test. For this, we also need to
remove mock intialization from the setup()-method and
annotate the mocks with #Mock
Remarks:
Instead of field injection, I would recommend constructor injection. This allows, among other things, to keep the structure of the code and create the unit under test within setup() by manual injection
I would also recommend to add a type to the when: when(someClient.createTennant(any(Request.class)))...
As was pointed out by #second, the spy on the unit under test is superfluous.
Also pointed out by #second was the fact that field injection will not work if a constructor is present
Using Mockito annotations (MockitoJUnitRunner.class, #InjectMocks and #Mock):
#RunWith(MockitoJUnitRunner.class)
public class TagRepositoryTest {
#InjectMocks
private TagRepository repository;
#Mock
private SetupDetails setupDetails;
....
}
I have the test target class using the injected dependency in the constructor:
public class TagRepository {
private final Collection<Tag> tags;
#Autowired
public TagRepository(SetupDetails setupDetails) {
this.tags = Arrays.asList(
new Tag("name", setupDetails.getSourceId()),
...
);
...
}
And I am currently stubbing the method call in #Setup or inside #Test with when():
when(setupDetails.getSourceId()).thenReturn("1");
This is not working as expected. Mockito seems to only stub the method call after the #InjectMocks TagRepository constructor is called, resulting in a null beeing returned instead of "1".
Is there a way to get the stub ready before the constructor is called (using Mockito annotations)?
The only way I am being able to work around this is trying to control the order Mockito setups this scenario giving up on Mockito annotations:
public void setUp() {
setupDetails = mock(SetupDetails.class);
when(setupDetails.getDbId()).thenReturn("1");
repository = new TagRepository(setupDetails);
}
Indeed this is the case and your "work around" is the way to go.
Some will argue that this is a good practice as your test will not compile when you introduce more members to your class under test, as you'll also add them to the constructor.
Let's say I have a class (OrchestratingClass) that has a method orchestrate() that calls a number of smaller methods of other classes (classA's do1() method, classB's do2() method). I would like to test the behavior of orchestrate() by mocking the responses of do1() and do2() with various permutations. I'm running my test with something like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public OrchestratingClassTest {
#Inject
private OrchestratingClass oc;
#Test
public void test1() {
// I would like to mock classA's do1() method to send back "1"
// I would like to mock classB's do2() method to send back "2"
}
#Test
public void test2() {
// I would like to mock classA's do1() method to send back "100"
// I would like to mock classB's do2() method to send back "200"
}
static class SimpleConfig {
#Bean
public InterfaceA interfaceA() {
return new ClassA();
}
#Bean
public InterfaceB interfaceB() {
return new ClassB();
}
#Bean
public OrchestratingClass orchestratingClass() {
return new OrchestratingClass();
}
}
}
And the orchestratingClass itself is quite basic, but I've added some sample code to aid in visualization:
#Named
public OrchestratingClass {
#Inject
private InterfaceA interfaceA;
#Inject
private InterfaceB interfaceB;
public String orchestrate() {
return interfaceA.do1() + " " + interfaceB.do2();
}
}
Now I'm aware I could tweak my SimpleConfig class to have the mocked out versions of classA and classB, but then I'm locked into 1 particular mock and can't "re-mock" things when I move onto test2(). I'm convinced that playing around with the java config files for 1 single test class would not work if we're trying to inject different "flavors" of beans "per-test". Does anyone have any recommendation on what I can do to make sure I'm really testing this thoroughly without being invasive (ex: adding superfluous "setters" for the specific classes in the orchestratingClass to side-step the bean injection pain)? Essentially, I'm looking to "tamper" the applicationContext on a per-test basis for specific beans of interest (along with the necessary housekeeping that's required) by applying a variety of mocks.
Here's a simple example using Mockito:
public class OrchestratingClassTest {
#Mock
private ClassA mockA;
#Mock
private ClassB mockB;
#InjectMocks
private OrchestratingClass oc;
#Before
public void prepare() {
MockitoAnnotations.initMocks(this);
}
#Test
public void shouldConcatenate() {
when(mockA.do1()).thenReturn("1");
when(mockB.do2()).thenReturn("2");
assertEquals("1 2", oc.orchestrate());
}
}
The magic happens in the call to MockitoAnnotations.initMocks(this), which will create mock instances for the fields annotated with #Mock, then create a real instance of Orchestrating class and inject its fields, thanks to #InjectMocks.
Note that, even without this magic, you could make your class easily testable by just adding a constructor taking ClassA and ClassB as arguments to OrchestratingClass, and annotate that constructor with #Autowired instead of annotating the fields. So, in short, use constructor injection rather than field injection.
I have a component setup that is essentially a launcher for an application. It is configured like so:
#Component
public class MyLauncher {
#Autowired
MyService myService;
//other methods
}
MyService is annotated with the #Service Spring annotation and is autowired into my launcher class without any issues.
I would like to write some jUnit test cases for MyLauncher, to do so I started a class like this:
public class MyLauncherTest
private MyLauncher myLauncher = new MyLauncher();
#Test
public void someTest() {
}
}
Can I create a Mock object for MyService and inject it into myLauncher in my test class? I currently don't have a getter or setter in myLauncher as Spring is handling the autowiring. If possible, I'd like to not have to add getters and setters. Can I tell the test case to inject a mock object into the autowired variable using an #Before init method?
If I'm going about this completely wrong, feel free to say that. I'm still new to this. My main goal is to just have some Java code or annotation that puts a mock object in that #Autowired variable without me having to write a setter method or having to use an applicationContext-test.xml file. I would much rather maintain everything for the test cases in the .java file instead of having to maintain a separate application content just for my tests.
I am hoping to use Mockito for the mock objects. In the past I have done this by using org.mockito.Mockito and creating my objects with Mockito.mock(MyClass.class).
You can absolutely inject mocks on MyLauncher in your test. I am sure if you show what mocking framework you are using someone would be quick to provide an answer. With mockito I would look into using #RunWith(MockitoJUnitRunner.class) and using annotations for myLauncher. It would look something like what is below.
#RunWith(MockitoJUnitRunner.class)
public class MyLauncherTest
#InjectMocks
private MyLauncher myLauncher = new MyLauncher();
#Mock
private MyService myService;
#Test
public void someTest() {
}
}
The accepted answer (use MockitoJUnitRunner and #InjectMocks) is great. But if you want something a little more lightweight (no special JUnit runner), and less "magical" (more transparent) especially for occasional use, you could just set the private fields directly using introspection.
If you use Spring, you already have a utility class for this : org.springframework.test.util.ReflectionTestUtils
The use is quite straightforward :
ReflectionTestUtils.setField(myLauncher, "myService", myService);
The first argument is your target bean, the second is the name of the (usually private) field, and the last is the value to inject.
If you don't use Spring, it is quite trivial to implement such a utility method. Here is the code I used before I found this Spring class :
public static void setPrivateField(Object target, String fieldName, Object value){
try{
Field privateField = target.getClass().getDeclaredField(fieldName);
privateField.setAccessible(true);
privateField.set(target, value);
}catch(Exception e){
throw new RuntimeException(e);
}
}
Sometimes you can refactor your #Component to use constructor or setter based injection to setup your testcase (you can and still rely on #Autowired). Now, you can create your test entirely without a mocking framework by implementing test stubs instead (e.g. Martin Fowler's MailServiceStub):
#Component
public class MyLauncher {
private MyService myService;
#Autowired
MyLauncher(MyService myService) {
this.myService = myService;
}
// other methods
}
public class MyServiceStub implements MyService {
// ...
}
public class MyLauncherTest
private MyLauncher myLauncher;
private MyServiceStub myServiceStub;
#Before
public void setUp() {
myServiceStub = new MyServiceStub();
myLauncher = new MyLauncher(myServiceStub);
}
#Test
public void someTest() {
}
}
This technique especially useful if the test and the class under test is located in the same package because then you can use the default, package-private access modifier to prevent other classes from accessing it. Note that you can still have your production code in src/main/java but your tests in src/main/test directories.
If you like Mockito then you will appreciate the MockitoJUnitRunner. It allows you to do "magic" things like #Manuel showed you:
#RunWith(MockitoJUnitRunner.class)
public class MyLauncherTest
#InjectMocks
private MyLauncher myLauncher; // no need to call the constructor
#Mock
private MyService myService;
#Test
public void someTest() {
}
}
Alternatively, you can use the default JUnit runner and call the MockitoAnnotations.initMocks() in a setUp() method to let Mockito initialize the annotated values. You can find more information in the javadoc of #InjectMocks and in a blog post that I have written.
I believe in order to have auto-wiring work on your MyLauncher class (for myService), you will need to let Spring initialize it instead of calling the constructor, by auto-wiring myLauncher. Once that is being auto-wired (and myService is also getting auto-wired), Spring (1.4.0 and up) provides a #MockBean annotation you can put in your test. This will replace a matching single beans in context with a mock of that type. You can then further define what mocking you want, in a #Before method.
public class MyLauncherTest
#MockBean
private MyService myService;
#Autowired
private MyLauncher myLauncher;
#Before
private void setupMockBean() {
doNothing().when(myService).someVoidMethod();
doReturn("Some Value").when(myService).someStringMethod();
}
#Test
public void someTest() {
myLauncher.doSomething();
}
}
Your MyLauncher class can then remain unmodified, and your MyService bean will be a mock whose methods return values as you defined:
#Component
public class MyLauncher {
#Autowired
MyService myService;
public void doSomething() {
myService.someVoidMethod();
myService.someMethodThatCallsSomeStringMethod();
}
//other methods
}
A couple advantages of this over other methods mentioned is that:
You don't need to manually inject myService.
You don't need use the Mockito runner or rules.
I'm a new user for Spring. I found a different solution for this. Using reflection and making public necessary fields and assign mock objects.
This is my auth controller and it has some Autowired private properties.
#RestController
public class AuthController {
#Autowired
private UsersDAOInterface usersDao;
#Autowired
private TokensDAOInterface tokensDao;
#RequestMapping(path = "/auth/getToken", method = RequestMethod.POST)
public #ResponseBody Object getToken(#RequestParam String username,
#RequestParam String password) {
User user = usersDao.getLoginUser(username, password);
if (user == null)
return new ErrorResult("Kullanıcıadı veya şifre hatalı");
Token token = new Token();
token.setTokenId("aergaerg");
token.setUserId(1);
token.setInsertDatetime(new Date());
return token;
}
}
And this is my Junit test for AuthController. I'm making public needed private properties and assign mock objects to them and rock :)
public class AuthControllerTest {
#Test
public void getToken() {
try {
UsersDAO mockUsersDao = mock(UsersDAO.class);
TokensDAO mockTokensDao = mock(TokensDAO.class);
User dummyUser = new User();
dummyUser.setId(10);
dummyUser.setUsername("nixarsoft");
dummyUser.setTopId(0);
when(mockUsersDao.getLoginUser(Matchers.anyString(), Matchers.anyString())) //
.thenReturn(dummyUser);
AuthController ctrl = new AuthController();
Field usersDaoField = ctrl.getClass().getDeclaredField("usersDao");
usersDaoField.setAccessible(true);
usersDaoField.set(ctrl, mockUsersDao);
Field tokensDaoField = ctrl.getClass().getDeclaredField("tokensDao");
tokensDaoField.setAccessible(true);
tokensDaoField.set(ctrl, mockTokensDao);
Token t = (Token) ctrl.getToken("test", "aergaeg");
Assert.assertNotNull(t);
} catch (Exception ex) {
System.out.println(ex);
}
}
}
I don't know advantages and disadvantages for this way but this is working. This technic has a little bit more code but these codes can be seperated by different methods etc. There are more good answers for this question but I want to point to different solution. Sorry for my bad english. Have a good java to everybody :)
Look at this link
Then write your test case as
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"/applicationContext.xml"})
public class MyLauncherTest{
#Resource
private MyLauncher myLauncher ;
#Test
public void someTest() {
//test code
}
}