Is it possible to mocking local variable by using JMockit? - java

Unit under test as following:
#Component(value = "UnitUnderTest")
public class UnitUnderTest {
#Resource(name = "propertiesManager")
private PropertiesManager prop;
public List<String> retrieveItems() {
List<String> list = new ArrayList<String>();
String basehome = prop.get("FileBase");
if (StringUtils.isBlank(basehome)) {
throw new NullPointerException("basehome must not be null or empty.");
}
File target = new File(basehome, "target");
String targetAbsPath = target.getAbsolutePath();
File[] files = FileUtils.FolderFinder(targetAbsPath, "test");//A utility that search all the directories under targetAbsPath, and the directory name mush match a prefix "test"
for (File file : files) {
list.add(file.getName());
}
return list;
}
}
Test case as below:
public class TestExample {
#Tested
UnitUnderTest unit;
#Injectable
PropertiesManager prop;
/**
*
*
*/
#Test
public void retrieveItems_test(#NonStrict final File target,#Mocked FileUtils util){
new Expectations(){
{
prop.get("FileBase");
result="home";
target.getAbsolutePath();
result="absolute";
FileUtils.FolderFinder("absolute", "test");
result=new File[]{new File("file1")};
}
};
List<String> retrieveItems = logic.retrieveItems();
assertSame(1, retrieveItems.size());
}
}
It's failed. The actual ressult of retrieveItems is empty. I found that "FileUtils.FolderFinder(targetAbsPath, "test")" is always return an empty File[]. That's really weird.
It probably because i mocked File instance "target" as well. It works fine if i only mocking the static method FileUtils.FolderFinder.
Does anyone know what the problem is? And is it possible to mock a local variable instance like i required here? Such as this target instance?
Thanks a lot!

The problem is that i should define which method i want to mock.
#Test
public void retrieveItems_test(#Mocked(methods={"getAbsolutePath"}) final File target,#Mocked FileUtils util){
new Expectations(){
{
prop.get("FileBase");
result="home";
target.getAbsolutePath();
result="absolute";
FileUtils.FolderFinder("absolute", "test");
result=new File[]{new File("file1")};
}
};
List<String> retrieveItems = logic.retrieveItems();
assertSame(1, retrieveItems.size());
}
This will be fine.

Related

Mock local variable in Junit, Mockito

I'm working on a test case for a code using Mockito. The code looks like this,
public class Example {
#Autowired
private HelperService hs;
public void someMethod() {
List<String> names = new ArrayList<>();
hs.addValues(names);
if(names.size() < 5) {throw new RuntimeException("Invalid names list");}
return;
}
}
public class HelperService {
public void addValues(List<String> names) {
names.add("alex");
names.add("harry");
names.add("james");
names.add("maria");
names.add("bob");
}
}
I know this is a contrived example but I have a similar usecase where I cannot modify the existing code. I want to unit test the Example class using Junit, Mockito. How can I test the exception scenario where names.size() is < 5.
I'm going to assume you already have a means for setting the HelperService field in your test (whether that's by making it a #SpringBootTest, using #InjectMocks, or something else). So this will just give options for providing one that will let you do what you want:
Extend HelperService and inject that:
// Inject this into your class under test
private HelperService hs = new LessThan5NameAddingHelperService();
class LessThan5NameAddingHelperService extends HelperService {
#Override
public void addNames( List<String> names ) {
names.add( "Dave" );
}
}
Provide a mock HelperService which does the same:
// Inject this into your class under test
private HelperService hs;
#Before
public void setupMockHelperService() {
hs = mock( HelperService.class );
doAnswer( invocation -> {
List<String> names = ( List<String> ) invocation.getArguments()[0];
names.add( "Dave" );
return null;
} ).when( hs ).addNames( any() );
}

JUnit/Mockito: How to mock or create a private member variable

I have a private String variable filePath that will be set in the SpringBoot's execute(..) method and then the value will be used in another method that will be called from inside this execute(..).
#Component("filebatchjobtask")
public class FileBatchJobTask extends BaseFileBatchJobTask implements Tasklet {
private String filePath; // PRIVATE VARIABLE THAT WILL BE USED IN A CALL
private static final CalLogger LOGGER = CalLoggerFactory.getLogger(FileBatchJobTask.class);
#Override
public RepeatStatus execute(final StepContribution stepContribution, final ChunkContext chunkContext) throws Exception {
// INITIALIZE PRIVATE VARIABLE HERE
filePath = chunkContext.getStepContext().getJobParameters().get(Constants.FILEPATH).toString();
processeFile(); // METHOD CALL WHERE FILEPATH INITIALIZED ABOVE WILL BE USED
return RepeatStatus.FINISHED;
}
#Override
protected void processeFile() throws IOException {
LOGGER.warn("FileBatchJobTask:processeFile():: Directory to process files: " + filePath);
File[] filelist = geteFiles(filePath); // THIS IS THE CALL I WANT TO MOCK
if (filelist == null || filelist.length < 1) {
LOGGER.warn("FileBatchJobTask: No eFiles available to process");
return;
}
LOGGER.warn("Total number of files to process: " + filelist.length);
}
It's corresponding test below:
//#RunWith(PowerMockRunner.class)
#RunWith(MockitoJUnitRunner.class)
public class FileBatchJobTaskTest extends BaseFileBatchJobTaskTest {
#InjectMocks
FileBatchJobTask fileBatchJobTask;
#Override
BaseFileBatchJobTask createFileBatchJobTask() {
return fileBatchJobTask;
}
#Test
public void processeFile() {
BaseFileBatchJobTask batchJobTask = Mockito.spy(createFileBatchJobTask());
// THIS resourceDir is the I want to use instead of filePath variable in tests here and pick file from this test resource path
Path resourceDir = Paths.get("src", "test", "resources", "data", "validation");
resourcePath = resourceDir.toFile().getAbsolutePath();
File fileDir = new File(resourcePath);
File[] files = fileDir.listFiles(new FileFilter() {
#Override
public boolean accept(final File pathname) {
String name = pathname.getName().toLowerCase();
return name.endsWith(".xml") && pathname.isFile();
}
});
doReturn(files).when(batchJobTask).geteFiles(anyString()); // THIS IS THE CALL I AM TRYING TO MOCK
try {
fileBatchJobTask.processeFile();
Assert.assertTrue(true);
} catch (...) {
}
}
This is the base class
class BaseFileBatchJobTask {
protected File[] geteFiles(final String eFileDirPath) {
File fileDir = new File(eFileDirPath); // NPE as eFileDirPath is null
File[] files = fileDir.listFiles(new FileFilter() {
#Override
public boolean accept(final File pathname) {
String name = pathname.getName().toLowerCase();
return name.endsWith(".xml") && pathname.isFile();
}
});
return files;
}
}
ERROR: I am getting NPE as when the test is run, getEFiles() is executed and filePath is null. Since I am mocking, it shouldn't go inside the actual implementation of the method. However, seems it's not being mocked as expected, so need help in figuring out the issue.
Also looked up a lot of SO posts but couldn't figure out the issue so please don't mark as duplicate if you don't know the answer :)
You need to call processeFile() on the spied version of your jobTask, not on the original one. Think about a spy being a wrapper around the spied object, that intercepts the mocked calls.
For short, just use batchJobTask inside the try-catch block like this:
try {
batchJobTask.processeFile();
Assert.assertTrue(true);
} catch (...) {
}

How to test method which returns another method using EasyMock?

I am writing test case using EasyMock. My test method calls "returns verification.getVerification(paramter 1, paramter 2, parameter 3)". When I invoke my test method from test class, it returns null.
Sharing my code snippet below:
//EntityField.java
private Class <? extends Entity> classtype;
private String paths;
Permission filter;
#Inject
private transient RestrictInterface restriction;
public EntityField(final Class <? extends Entity> classtype, final String
path, final Permission filterclass)
{
this.classtype = classtype;
this.paths = path;
filter = filterclass;
}
public Permission getBasePermission() //my test method
{
if(Active.class.isAssignableFrom(classtype))
{
filterclass=new
SimplePermission(Active.active_attribute,Operator.equals,Boolean.TRUE);
}
else if (NotActive.class.isAssignableFrom(classtype))
{
filterclass=new
SimplePermission("notactive",Operator.equals,Boolean.TRUE);
}
return restriction.getBasePermission(classtype,filterclass);
}
//Test.java
#Test
public void testgetBaseRestriction() {
//NiceMock
EntityField entityfieldobject = new EntityField (classtype, path,
filterclass);
//Mock Objects
RestrictInterface restriction = createNiceMock(RestrictInterface.class);
Permission filter = new
SimplePermission(Active.active_attribute,Operator.equals,Boolean.TRUE);
final Class = Active.class;
//expects
expect(restriction.getBaseRestriction(eq(classtype),eq(filterclass)))
.andStubReturn(filter);
//replay
replay(restriction);
Permission object = entityfieldobject.getBasePermission();
// here object returns null
verify(restriction);
}
I wanted to test whether filterclass value is set or not in my test class.
How to avoid this null value in test case. Any help would be appreciated.
Thanks
Updated answer, now that I have full code:
restriction doesn't seem injected in entityfieldobject, So the null is normal. EasyMock is not aware of #Inject. Please do inject the dependency yourself. I recommend to use constructor injection for that.
The code below gives a good example.
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.mock;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertNotNull;
public class TestClass {
#Test
public void testgetBaseRestriction() {
Verification verification = mock(Verification.class);
expect(verification.getVerification("1", "2", "3")).andReturn(new Permission());
replay(verification);
EntityField entityfieldobject = new EntityField(verification);
assertNotNull(entityfieldobject.getVerification());
}
}
class Permission {}
interface Verification {
Permission getVerification(String s1, String s2, String s3);
}
class EntityField {
private final Verification verification;
public EntityField(Verification verification) {
this.verification = verification;
}
public Permission getVerification() {
return verification.getVerification("1", "2", "3");
}
}

JUnit test - method called on class instance

I have a problem with JUnit test for my method
#Transactional
#Override
public void deleteOffer(Offer offer) {
List<String> offerPictures = this.getOfferPictures(offer);
if (offerPictures != null) {
System.out.println(offerPictures.size());
for (String stringName : offerPictures) {
this.deleteSinglePhoto(new File(hardDiscAddress + stringName));
this.deleteSinglePhoto(new File(hardDiscAddress + "sm_" + stringName));
}
}
offerDAO.delete(offer.getId());
}
I already have test for empty offerPcitures list, but now I need to write one for NOT empty list. Problem is I don't know how to mock getOfferPictures method to return not empty string list
#Override
public List<String> getOfferPictures(Offer offer) {
File dir = new File(hardDiscAddress);
List<String> resultantlist = new ArrayList<String>();
if (dir.isDirectory()) {
for (final File f : dir.listFiles()) {
if (f.getName().startsWith(offer.getPhotography())) {
resultantlist.add(f.getName());
}
}
}
return resultantlist;
}
And this is the test for empty list
#Test
public void testDeleteOffer() {
// given
testOfferServiceImpl = new OfferServiceImpl();
testOfferServiceImpl.hardDiscAddress = "C:/";
testOfferServiceImpl.offerDAO = offerDAOMock;
when(offerMock.getId()).thenReturn(1);
when(offerMock.getPhotography()).thenReturn("stringForTest");
doNothing().when(offerDAOMock).delete(1);
// when
testOfferServiceImpl.deleteOffer(offerMock);
// then
Mockito.verify(offerDAOMock, times(1)).delete(1);
}
You could use Mockito.spy to partially mock the instance you're testing, and return a non empty list:
#Test
public void testNotEmptyOffer() {
// Given
testOfferServiceImpl = new OfferServiceImpl();
testOfferServiceImpl.hardDiscAddress = "C:/";
testOfferServiceImpl.offerDAO = offerDAOMock;
// Spy (partially mock) the object
testOfferServiceImpl = Mockito.spy(testOfferServiceImpl);
doReturn(Arrays.asList("one", "two", "three")).
when(testOfferServiceImpl).getOfferPictures(offerMock)
// Test your logic here
}
Use something like Mockito. You can do:
Candidate candidate = mock(Candidate.class);
when(candidate.getFirstName()).thenReturn("Bob");
this is an example from project, works well. You will also have to annotate your test class with:
#RunWith(MockitoJUnitRunner.class)
you can then make the method return whatever you like. Hope that helps :)

how to initialize common resource names in multiple junit4 test classes

I am creating a set of junit test classes ,all of which read from the same input data files.I created a test suite as below,but found that I would be replicating the filenames in each test class.
So, how do I do this without repeating the code..
#RunWith(Suite.class)
#SuiteClasses({SomeTests.class,someOtherTests.class})
public class AllTests{
}
-------------------
public class SomeTests{
private String[] allfiles;
public SomeTests() {
allfiles = new String[] {"data1.txt","data2.txt"};
}
#Test
public void testXX1(){
//
}
#Test
public void testXX2(){
//
}
}
public class someOtherTests{
private String[] allfiles;
public someOtherTests() {
allfiles = new String[] {"data1.txt","data2.txt"};
}
#Test
public void testYY(){
//
}
}
I thought I would have to make another class to provide the filenames as a String array..sothat the test classes can initialize the allfiles variable by calling the getFileNames() static method,combining this this with BeforeClass annotation
public class FileNames {
public static String[] getFileNames() {
return new String[]{"data1.txt","data2.txt"};
}
}
public class SomeTests{
private String[] allfiles;
public SomeTests() {
}
#BeforeClass
public void setUp(){
allfiles = FileNames.getFileNames();
}
#Test
public void testXX1(){
//
}
#Test
public void testXX2(){
//
}
}
but I am not sure that is the right way. This will require setUp() to be declared as static ,and that means I will have to make the instance variable allfiles static !
I think this is a common scenario in junit testing ..so can someone please tell me how to do this properly?
Use #Before instead of #BeforeClass, then your setUp() method need not be static.
However, unless you are going to modify your filename array in your tests, you could also create a base class for your tests and declare a protected constant with those names:
public class FileBasedTests {
protected static final String[] FILENAMES = {"data1.txt","data2.txt"}
}
public class SomeTests extends FileBasedTests {
...
}
If you really are concerned about each test having its own copy of those file names, you can write allFiles = FILENAMES.clone().

Categories

Resources