So I have a #Spy which performs a new object creation, related to the refactoring pattern of -> (Method to Object) however, that newly created instance does not have its dependent services injected in.
The code is obviously not my property to post up on this forum, but in pseudo logic, Ill try to get the message across below:
#Mock private SpecialistService specialistServiceMock;
#InjectMocks private TestObject testObj = new TestObject();
although TestObject inherits this service from its Abstract parent class, and any usage directly in testObj the specialistServiceMock is not null and works fine.
Now, when testObj hits the new RefactoredMethodToObject() class, and calls its invoke() method, it needs to have specialistServiceMock to do a few things, but specialistServiceMock is null.
I appreciate this looks to be beyond Mockito's capability, I do have PowerMock at hand too.
So in a nutshell, I need to have the specialistServiceMock mocked for actions needed to be performed in the dynamically created instance of RefactoredMethodToObject().
Any ideas would be welcome, and if you need more information, let me know. Thanks
Related
So I am writing a class which I want to follow the best practices and be testable.
I have a new object to be created inside it. So, I am following the factory pattern to achieve it.
public class Apple {
// factory object injected in class
private SeedFactory seedFactory;
// Method to be tested
public void myMethod(String property1, int property2, String depends) {
// Just to set the necessary parameter
seedFactory = new SeedFactory(property1, property2);
// Factory pattern intact. Instance generation depends on only one parameter
SeedFactory result = seedFactory.getInstance(depends);
}
}
EDIT: Adding code for factory as well.
public class SeedFactory{
String property1;
int property2;
SeedFactory(property1,property2){
this.property1 = property1;
this.property2 = property2;
}
SeedFactory getInstance(int depends){
if(depends == 1)
{ // do stuff }
else{ // do stuff and return instance }
Now, before I actually create the new object, I have to make sure that I set two properties for the new instance to be generated, which are needed to be present irrespective of the type of instance generated by the factory. depends is the actual parameter which tells the factory what instance to return.
Now, as far as testability of this code is concerned, I can user PowerMockito to mock the factory object using whenNew but using PowerMockito is not a choice. I have to make it testable without it.
Also, I have tried to encapsulate the new call within a one line function and then use spy. But I want to avoid using spy, since it is not considered a good practice, in context of where this code is being used as a whole.
So my question is, Is there any way, without using PowerMockito, to re-write this class so that it can be unit tested properly?
If the instance to be generated needed only one parameter, then it would have been trivial. However, I don't want to pass more than one parameter to getInstance().
SeedFactory is not Apple's dependancy but your method depends on SeedFactory which has "uses" relationship. So to define proper relation i would suggest you use "USES" relation as below:
public void myMethod(SeedFactory seedFactory, String depends){ // Method to be tested
Now you could mock SeedFactory and can unit test it appropriately.
I think you're doing something wrong.
If SeedFactory isn't an Apple's dependency but an internal concern, hence you don't need to mock a SeedFactory to test Apple. You should test the public API provided by Apple only.
If SeedFactory is an Apple's dependency, so it definitely should be injected.
I want to mock dao creation for following method.
private ReturnType createTenant(){
TenantDto tenantDto = new TenantDto();
TenantGroupDto tenantUserGroupDto = new TenantGroupDto(DEFAULT_USER_GROUP_NAME,Type.HUMAN,DEFAULT_USER_GROUP_DESCR, true);
TenantGroupDto tenantDeviceGroupDto = new TenantGroupDto(DEFAULT_DEVICE_GROUP_NAME,Type.DEVICE,DEFAULT_DEVICE_GROUP_DESCR, true);
Set<TenantGroupDto> tenantGroups = new HashSet<TenantGroupDto>();
tenantGroups.add(tenantUserGroupDto);
tenantGroups.add(tenantDeviceGroupDto);
tenantDto.setTenantGroup(tenantGroups);
tenantDto = tenantDao.create(tenantDto);
return someOtherOperation(tenantDto);
}
I'm able to mock rest of the things however. I'm unable to mock generic creation.
i.e.
Set<TenantGroupDto> tenantGroups = new HashSet<TenantGroupDto>();
It is required to be mocked since tenantGroups is parameter to
tenantDao.create(tenantDto);
Most of the links/questions I search about are when the generic object gets returned from some method. I couldn't find any solution to creation of generic object. Any help is appreciated.
Thx in Advance.
This is how to create a mock of a generic class.
#Mock
Set<TenantGroupDto> tenantGroups
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
#Test
public void myTest(){
when(tenantGroups....
}
Mockito (alone) can't truly mock the instantiation of objects, Generics or otherwise (although you can get close).
This is a classic reason why people use the Factory pattern, allowing pluggable factories to allow differing types of objects decided at runtime, or to allow neat, encapsulated testing with mocks / stubs like in this situation.
As for the collections (e.g. HashSet), there is very little reason to test them; just make sure your (domain) objects are fully tested, and you should be covering the right code in your tests.
I am new to Spring and JUnit. I need to mock a class which is derived from ApplicationContextAware class which is inside my toBeTested(getList) method. In the following short code snippet, I need to test the getList method in abc class.
I am able to mock ModulesConfigRegistry because there is a setter for it. But I am not able to mock ModuleConfig and ListProvider. Both ModulesConfigRegistry and ModuleConfig have implemented ApplicationContextAware so it returns classes from bean. ListProvider.getList(lst.getList in code) is the method which makes further calls up to database and is required to be mocked. Appreciate your help in advance. Code sample will be helpful as I am new to Spring and JUnit.
class abc {
private ModulesConfigRegistry modulesConfigRegistry;
public void setModulesConfigRegistry(ModulesConfigRegistry modulesConfigRegistry) {
this.modulesConfigRegistry = modulesConfigRegistry;
}
public List getList(String name, String moduleName)
{
ModuleConfig moduleConfig = modulesConfigRegistry.getModuleConfig(moduleName);
Object mlist = moduleConfig.getListProvider(name);
if(mlist instanceof ListProvider)
{
ListProvider lst = (ListProvider)mList;
}
return lst.getList("abc");
}
}
Maybe there is another more simple way to achieve this (not mandatory the best). In my experience I've used Reflection in Java when it's up to Unit-testing. After all, to me the main purpose of the unit tests is to simply exercise smallest testable part and nothing more. That's why I simply use my dummy-test-object and get/set fields/properties I need.
But one thing that must be considered here is that reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects. So if you know what your doing it's a good alternative.
Since you already using
JUnit
One very common use case in Java is the usage with annotations. JUnit 4, for example, will use reflection to look through your classes for methods tagged with the #Test annotation, and will then call them when running the unit test.
If you want to consider it and use it - here you can find some good examples.
Cheers.
One approach here is create mock objects for each object that you need to interact with ModuleConfig and ListProvider
#RunWith(MockitoJUnitRunner.class)
public class abcTest{
#InjectMocks
private abc abcInstance;
#Mock
private ModulesConfigRegistry modulesConfigRegistry ;
#Test
private voidTestGetList(){
//Create the mock and interactions
ModuleConfig moduleConfigMock = Mockito.mock(ModuleConfig.class);
ListProvider listProviderMock = Mockito.mock(ListProvider.class);
ArrayList listToReturn = new ArrayList();
Mockito.when(modulesConfigRegistry.getModuleConfig(Mockito.anyString())).thenReturn(moduleConfigMock);
Mockito.when(moduleConfigMock.getListProvider(Mockito.anyString())).thenReturn(listProviderMock);
Mockito.when(listProviderMock.getList(Mockito.anyString())).thenReturn(listProviderMock);
//Call real method
List resultList = abcInstance.getList("stringInput1", "stringInput2");
//Make assertions
}
}
Basically you need to create mock objects for any of the instances that you get from a mock object and use mockito to define the result of its method.
Other options is create a new class that implements or is a subclass of the returned object type and override the methods.
I have a class which takes a message with payload String.
The payload is then split and used to create an Entity which is passed to DAOInterface to persist.
How can you test the call daoInterface.insert(entity) has been made?
To Mock the DAOInterface and then verify the call to DAO requires the entity in the test class i.e.
verify(daoInterface).insert(entity);
Is this bad design i.e. creating the entity at this stage? Should the Sting[] split be passed to the DAOImplementaion and initialized there. Example problem,
public class ServiceClass {
#AutoWire
private DAOInterface daoInterface;
public void serviceMessage(Message<String> message) {
MessageHeaders mh = new MessageHeaders(message.getHeaders());
String[] split = ((String) mh.get("payload")).split("_");
code omitted
...
String type = mh.get("WhatType");
Entity entity = new Entity(split[0], split[1], split[2]);
if (type.equals("one"))
{
daoInterface.insert(entity); //How to test?
}
else
{
if (type.equals("two"))
{
doaInterface.modify(entity); //How to test?
}
}
}
}
You can verify with Mockito Matchers.
If you only care that the method is called with some Entity, you can verify that with
verify(daoInterface).insert(any(Entity.class));
If you care about which Entity, and the Entity class has an equals method, you can make an entity that should be equal to the one created and verify with
verify(daoInterface).insert(eq(expectedEntity);
If it's more complex than either of these cases, you can also write your own argument matchers.
The easiest thing you can do is injecting another collaborator to the service which will transform payload to Entity. This way you can keep control on object creation (Inversion of Control). Something like the example below injected to the ServiceClass should do the job:
interface PayloadTransformer {
public Entity transform(String payload);
}
This way your code will be easy to test and you split responsibilities which is usually a good thing. Have a look on Single Responsibility principle
Pushing transformation logic down to dao is almost never a good idea.
BTW. you can write else if without additional brackets and indentations. It's more readable like:
if (a) {
// do something
} else if (b) {
// do something
} else {
// do something
}
The last advice ServiceClass is really poor name for class. The word class is redundant here. Just name it Service, EntityService, MessageService or something which fits your case well.
I wouldn't name field with suffix *Interface as well. Underneath is some implementation injected, I assume. Better name it entityDao or just dao. It's up to you though :)
If you use a test framework like PowerMock, you can invoke private constructors and private methods in your test. This makes it easy to inject mock objects like a mock DAOInterface so you can retrieve it later and test it's been called.
For example, in PowerMock, to call a private constructor:
public class ServiceClass{
#Autowire
private final DAOInterface dao;
public ServiceClass() {
}
private ServiceClass(DAOInterface dao) {
this.dao = dao;
}
}
You simply do:
PrivateConstructorInstantiationDemo instance = WhiteBox.invokeConstructor(
PrivateConstructorInstantiationDemo.class,
new MockDAOInterface() );
So if you're using a dependency inject framework like above, this dovetails nicely. You don't normally have the dependency injection working during test, since it usually requires booting a large chunk of code with a lot of configuration.
By adding a single private constructor, you avoid breaking encapsulation, but you can still inject your mock object into the code during test with a test framework like PowerMock. This is considered best practice.
You could break encapsulation and add publicly accessible methods or ctors to the SeviceClass, but if you don't need them for your design it's not good practice to add them only for test. That's why people put such effort into bypassing encapsulation in frameworks like Mockito and PowerMock. It's not just a dodge around private code, it's because you want to keep the encapsulation while still being able to test.
EDIT:
If you're not familiar with making mock objects, you should do some Google searches on the subject. It's very common and a good skill to have. With the above code, you could make your own mock object. But making mocks is so common that most test frameworks will do this for you.
For example, in PowerMock, I just looked at their page on making mocks here. You can make a mock like this
DAOInteface myMock = createMock(DAOInterface.class);
You can then ask the mock to verify that methods are called:
expect(myMock.someMethod());
Now the mock 'expects' that method to be called, and if it isn't, it'll generate an error for your test. Pretty sweet actually.
You can also return values from a call:
expect(myMock.insert()).andReturn("Test succeeded");
so your code would then see the value "Test succeeded" when it called that method. I don't see that 'insert' does return a value, that's just an example.
So lets say I have a class
class JustAClass() {
Stirng justAField = "nothing";
}
Now I'm testing this class and I put it into a mock
JustAClass realClass = newJustACLass();
JustAClass spyClass = Mockito.spy(realClass);
spyClass.justAField = "something"
Question is: What does the realClass.justAField equal now?
EDIT: In response to #fge
This didn't fail.
CSVExport spyClass = Mockito.spy(testClass);
FileOutputStream wFile = Mockito.mock(FileOutputStream.class);
spyClass.wFile = wFile;
Mockito.doThrow(IOException.class).when(spyClass).createBlankWorkbook();
spyClass.export(testEnabledFields);
Mockito.doThrow(IOException.class).when(wFile).close();
spyClass.export(testEnabledFields);
So is the wFile in testClass the mock now, or the original?
Pulling this from api doc http://docs.mockito.googlecode.com/hg-history/be6d53f62790ac7c9cf07c32485343ce94e1b563/1.9.5/org/mockito/Spy.html
Mockito does not delegate calls to the passed real instance, instead it actually creates a copy of it. So if you keep the real instance and interact with it, don't expect the spied to be aware of those interaction and their effect on real instance state. The corollary is that when an unstubbed method is called on the spy but not on the real instance, you won't see any effects on the real instance