How to call a parameterized method (using dataprovider) from a different class? - java

I am facing an issue wherein I have created a parameterized method that uses dataprovider. Both DataProvider and method and created in same class. Now, I want to call this method from another class but it requires parameters to be passed which I cannot since they are being read from dataProvider.
I have tried declaring the dataProvider in different class too but that doesn't work. Please suggest some workaround for it.
NOTE: I have a restriction that I cannot use TestNG.xml to implement this scenario.
Please find the code below:
DataProvider:
#DataProvider(name = "TestSuite")
public Object[][] dataSheetTraverser() {
String SheetName = "ProgLang";
datatable = new Xls_Reader(TestDataSheetPath_ProgLang);
int rowcount = datatable.getRowCount(SheetName);
Object result[][] = new Object[rowcount - 1][3];
for (int i = 2; i < rowcount + 1; i++) {
result[i - 2][0] = SheetName;
result[i - 2][1] = i;
result[i - 2][2] = datatable.getCellData(SheetName, "caseType", i);
}
return result;
}
Test Method:
#Test(dataProvider="TestSuite_ProgLang",priority =2)
public void TC_Verify_EditProgLang(String SheetName,int i, String caseType)
{
String test1= datatable.getCellData(SheetName, "Skills", i);
String test2= datatable.getCellData(SheetName, "Version", i);
String test3= datatable.getCellData(SheetName, "LastUsed", i);
String test4= datatable.getCellData(SheetName, "ExperienceYr", i);
String ExperienceMn = datatable.getCellData(SheetName, "ExperienceMn", i);
proglang.FillForm_ProgLang(Skills, Version, LastUsed, ExperienceYr, ExperienceMn);
}
I want to call the above function TC_Verify_EditProgLang from another class. Please suggest.

You can use the dataProviderClass attribute for calling from other class
in #Test and The Provider method Must be static :
public class StaticProvider {
#DataProvider(name = "create")
public static Object[][] createData() {
return new Object[][] {
new Object[] { new Integer(42) }
};
}
}
//different Class
public class MyTest {
#Test(dataProvider = "create", dataProviderClass = StaticProvider.class)
public void test(Integer n) {
// ...
}
}
please check the Documentation :dataProviders

Related

Can we make sure #beforesuite gets called before dataprovider?

Can we follow the below method to initialise the test data? There are 2 points I want to implement.
Need to initialise/load the test data once from the file and use the same test data in all dataproviders.Thought to implement test data loader in #beforesuite class.
Need data from dataprovider and a parameter from testNG file at the same time in #test method.
#BeforeSuite
#Parameters(value = { "test_data_file" })
public static synchronized void init(String test_data_file) {
TestDataFactory.load(test_data_file);
}
#Test(dataProvider="dp_dummy",dataProviderClass = DP_1.class)
public void testDummyAPI(TestData test_data,ITestContext context){
String param = context.getCurrentXmlTest().getParameter("param");
}
#DataProvider(name = "dp_dummy")
public Object[][] getDataFromDataprovider(ITestContext context) {
List<TestData> test_data_collection = TestDataFactory.getTestData(targated_test_data);
Object[][] test_data_set = new Object[test_data_collection.size()][1];
for(TestData test_data : test_data_collection)
test_data_set[i++][0] = test_data;
return test_data_set;}
Assuming you are creating your test_data_set correctly you can achieve your second point like this
#Test(dataProvider="dp_dummy",dataProviderClass = DP_1.class)
public void testDummyAPI( String p, Object[][] ob){
System.out.println(p);
System.out.println(ob[0][0]);
}
#DataProvider(name = "dp_dummy")
public Object[][] getDataFromDataprovider(ITestContext context) {
List<TestData> test_data_collection = TestDataFactory.getTestData(targated_test_data);
Object[][] test_data_set = new Object[test_data_collection.size()][1];
for(TestData test_data : test_data_collection)
test_data_set[i++][0] = test_data;
String param = context.getCurrentXmlTest().getParameter("param");
return new Object[][] {
{ param, test_data_set}
};
}

My mock is not being used by my program

I have a program that I want to mock data for using Mockito.
My main program is AdDataAggregate and it calls AdDataConnect.
AdDataConnect makes a call to an API that returns a string that is parsed into JSON and aggregated.
I've created the mocks and they return data but they are not being used by the main program.
Can someone please show me the error of my ways. Thanks in advance for your help.
//Main Program
public class AdDataAggregate {
public List<AdData> processInfo(long[] adIds){
AdDataConnect adDataConnect = new AdDataConnect();
List<AdData> adAccumData = new ArrayList<AdData>();
for (long adId: adIds) {
data = adDataConnect.connectToData(adId); <———— method to Mock.
} 
 }
}
//Test Program
#RunWith(MockitoJUnitRunner.class)
public class AdDataTest {
 
#InjectMocks
private AdDataAggregate adDataAggregate = new AdDataAggregate();
#Mock
private AdDataConnect adDataConnect;
private String oneAdId =
"[{\"advertiser_id\":\"1\",\"ymd\":\"2015-12-" +
"07\",\"num_clicks\":10,\"num_impressions\":100}," +
"{\"advertiser_id\":\"1\",\"ymd\":\"2015-12-" +
"06\",\"num_clicks\":20,\"num_impressions\":200}," +
"{\"advertiser_id\":\"1\",\"ymd\":\"2015-12-" +
"05\",\"num_clicks\":30,\"num_impressions\":300}]";

 #Test
public void testWithOneAdId(){
MockitoAnnotations.initMocks(this);
adDataConnect = mock(AdDataConnect.class);
adDataAggregate = mock(AdDataAggregate.class);
when(adDataConnect.connectToData(eq(1L)))
.thenReturn(oneAdId);
String myString = adDataConnect.connectToData(1L);
long[] adIds = new long[]{1L};
List<AdData> outData = adDataAggregate.processInfo(adIds);
Assert.assertEquals(1, outData.size());
Assert.assertEquals(myString, oneAdId);
Assert.assertEquals(60, outData.get(0).getNumImpressions());
Assert.assertEquals(600, outData.get(0).getNumImpressions());
}
}
You need to inject the AdDataConnect into your AdDataAggregate instead of instantiating it. When you instantiate it from within AdDataAggregate you are forcing an implementation to be used. You need to allow someone from the outside to set it so that you can set the mocked version in your tests.
Here is how you do it. Pass the AdDataConnect in the constructor:
public class AdDataAggregate
{
private AdDataConnect adDataConnect;
public AdDataAggregate(AdDataConnect adDataConnect)
{
this.adDataConnect = adDataConnect;
}
public List<AdData> processInfo(long[] adIds)
{
List<AdData> adAccumData = new ArrayList<AdData>();
for(long adId : adIds)
{
data = adDataConnect.connectToData(adId);
}
}
}
Then in your test do this. You can see my comment where I used the new constructor:
#RunWith(MockitoJUnitRunner.class)
public class AdDataTest
{
private AdDataAggregate adDataAggregate;
#Mock
private AdDataConnect adDataConnect;
private String oneAdId = "[{\"advertiser_id\":\"1\",\"ymd\":\"2015-12-"
+ "07\",\"num_clicks\":10,\"num_impressions\":100}," + "{\"advertiser_id\":\"1\",\"ymd\":\"2015-12-"
+ "06\",\"num_clicks\":20,\"num_impressions\":200}," + "{\"advertiser_id\":\"1\",\"ymd\":\"2015-12-"
+ "05\",\"num_clicks\":30,\"num_impressions\":300}]";
#Test
public void testWithOneAdId()
{
MockitoAnnotations.initMocks(this);
adDataAggregate = new AdDataAggregate(adDataConnect);//PASS THE MOCK HERE
when(adDataConnect.connectToData(eq(1L))).thenReturn(oneAdId);
String myString = adDataConnect.connectToData(1L);
long[] adIds = new long[] { 1L };
List<AdData> outData = adDataAggregate.processInfo(adIds);
Assert.assertEquals(1, outData.size());
Assert.assertEquals(myString, oneAdId);
Assert.assertEquals(60, outData.get(0).getNumImpressions());
Assert.assertEquals(600, outData.get(0).getNumImpressions());
}
}

EasyMock: How to Verify Method Order for Set of Values Where Order of Set Does Not Matter

I have a test in which I have a set of specific values for which two different methods will execute once for each value in the set. I need to check that the two methods are called in a specific order in relation to each other, but not in relation to the order of the set of values. For example:
String[] values = { "A", "B", "C" };
for (...<loop over values...) {
methodOne(value);
methodTwo(value);
}
It does not matter which order values is in, but I need to verify that methodOne() and methodTwo() are called for each value in the set AND that methodOne() is always called before methodTwo().
I know that I can create a control and expect methodOne() and methodTwo() for each value, then do control.verify(), but this depends on values being in a specific order.
Is there an elegant way to do this?
Thanks
You can do this using andAnswer().
Basically, inside the andAnswer() from methodOne() you set some variable to hold what the passed in value was.
Then in the andAnswer() for methodTwo() you assert that the same argument matches what you saved from your methodOne answer.
Since each call to methodOne will modify this variable it will make sure methodTwo() is always called after methodOne().
Note this solution is not thread safe
First you need something to hold the variable from the methodOne call. This can be a simple class with a single field or even an array of one element. You need this wrapper object because you need to reference it in the IAnswer which requires a final or effectively final field.
private class CurrentValue{
private String methodOneArg;
}
Now your expectations. Here I called the class that you are testing (The System Under Test) sut:
String[] values = new String[]{"A", "B", "C"};
final CurrentValue currentValue = new CurrentValue();
sut.methodOne(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
//save the parameter passed in to our holder object
currentValue.methodOneArg =(String) EasyMock.getCurrentArguments()[0];
return null;
}
}).times(values.length); // do this once for every element in values
sut.methodTwo(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
String value =(String) EasyMock.getCurrentArguments()[0];
//check to make sure the parameter matches the
//the most recent call to methodOne()
assertEquals(currentValue.methodOneArg, value);
return null;
}
}).times(values.length); // do this once for every element in values
replay(sut);
... //do your test
verify(sut);
EDIT
you are correct that if you are using EasyMock 2.4 + you can use the new Capture class to get the argument value in a cleaner way for methodOne(). However, you may still need to use the andAnswer() for methodTwo() to make sure the correct values are called in order.
Here is the same code using Capture
Capture<String> captureArg = new Capture<>();
sut.methodOne(and(capture(captureArg), isA(String.class)));
expectLastCall().times(values.length);
sut.methodTwo(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
String value =(String) EasyMock.getCurrentArguments()[0];
assertEquals(captureArg.getValue(), value);
return null;
}
}).times(values.length);
replay(sut);
For those interested, I solved this issue using intended EasyMock functionality. The solution was to make a custom IArgumentMatcher to verify against a collection of values and to enforce how many times each value is matched consecutively. The custom matcher, in addition to using strict mocking exactly solves the original problem.
public class SetMatcher implements IArgumentMatcher {
private List<String> valuesToMatch;
private List<String> remainingValues;
private String currentValue = null;
private int timesMatched = 0;
private int setMatches;
public SetMatcher(final List<String> valuesToMatch, final int times) {
this.valuesToMatch = new ArrayList<String>(valuesToMatch);
this.remainingValues = new ArrayList<String>(valuesToMatch);
this.setMatches = times;
}
public String use() {
EasyMock.reportMatcher(this);
return null;
}
public void appendTo(StringBuffer buffer) {
if (this.remainingValues.size() == 0) {
buffer.append("all values in " + this.valuesToMatch + " already matched " + this.setMatches + " time(s)");
} else {
buffer.append("match " + this.valuesToMatch + " " + this.setMatches + " time(s) each");
}
}
public boolean matches(Object other) {
if (this.timesMatched >= this.setMatches) {
this.currentValue = null;
this.timesMatched = 0;
}
if (null == this.currentValue) {
if (this.remainingValues.contains(other)) {
this.currentValue = (String) other;
this.timesMatched = 1;
this.remainingValues.remove(other);
return true;
}
} else if (this.currentValue.equals(other)) {
this.timesMatched++;
return true;
}
return false;
}
}
The class being tested:
public class DataProcessor {
private ServiceOne serviceOne;
private ServiceTwo serviceTwo;
public DataProcessor(ServiceOne serviceOne, ServiceTwo serviceTwo) {
this.serviceOne = serviceOne;
this.serviceTwo = serviceTwo;
}
public void processAll(List<String> allValues) {
List<String> copy = new ArrayList<String>(allValues);
for (String value : copy) {
this.serviceOne.preProcessData(value);
this.serviceTwo.completeTransaction(value);
}
}
}
And the test:
public class DataProcessorTest {
List<String> TEST_VALUES = Arrays.asList("One", "Two", "Three", "Four", "Five");
#Test
public void test() {
IMocksControl control = EasyMock.createStrictControl();
ServiceOne serviceOne = control.createMock(ServiceOne.class);
ServiceTwo serviceTwo = control.createMock(ServiceTwo.class);
SetMatcher matcher = new SetMatcher(TEST_VALUES, 2);
for (int i = 0; i < TEST_VALUES.size(); i++) {
serviceOne.preProcessData(matcher.use());
serviceTwo.completeTransaction(matcher.use());
}
control.replay();
DataProcessor dataProcessor = new DataProcessor(serviceOne, serviceTwo);
dataProcessor.processAll(TEST_VALUES);
control.verify();
}
}
The test will fail for any of the following:
ServiceOne and ServiceTwo are called in the wrong order
ServiceOne and ServiceTwo are not called consecutively with the same value
ServiceOne or ServiceTwo are called with a value that is not in the specified value list
A call is made beyond the number of expected times for a value in the list

Get null value from another object in Java, but get value in own class

When I try to execute this code, after I choose AMD, I got null in value. how it can be happen ?
below is the source code :
[for main]
public class processor{
public int hargapro;
public String nmbarangpro;
public static final Scanner input = new Scanner(System.in);
public String getpro()
{
return nmbarangpro;
}
public int getproharga()
{
return hargapro;
}
public void daftarpro() {
List<String> daftarpro = new ArrayList<>();
daftarpro.add("AMD");
daftarpro.add("Intel");
List<String> nomer = new ArrayList<>();
nomer.add("1. ");
nomer.add("2. ");
System.out.println("Processor yang tersedia :");
for (int i = 0; i < daftarpro.size(); i++) {
System.out.println(nomer.get(i)+daftarpro.get(i));
}
System.out.println("Pilihan anda : ");
int pilih = input.nextInt();
switch(pilih)
{
case 1:
{
System.out.println("Anda membeli Processor AMD");
System.out.println("Seharga Rp 1.200.000");
harga(1200000); //call harga method
namabarang("AMD"); //call namabarang method
System.out.println(getpro()); //[for testing]filled with AMD[ni problem here]
System.out.println(getproharga()); //[for testing][filled with 1200000[no problem here]
break;
}
case 2:
{
System.out.println("Anda membeli Processor AMD");
System.out.println("Seharga Rp 1.200.000");
harga(1500000);
namabarang("Intel");
break;
}
default:
System.out.println("Pilihan tidak tersedia");
daftarpro();
}
}
#Override
public int harga(int hargamasuk) {
return hargapro = hargamasuk;
}
#Override
public String namabarang(String barang) {
return nmbarangpro = barang;
}
public static void main(String[] args) {
processor a = new processor();
a.daftarpro();//get menu from daftarpro()
kasir x = new kasir();
x.semua();//get null in value
}
}
my second files :
public class kasir {
public void semua()
{
processor a = new processor();
System.out.println(a.getpro());
}}
When I try to read value through class kasir, i get x.semua filled with null value. how it can be happen ?
Your semua method creates a new instance of processor which it then reads from:
public void semua()
{
processor a = new processor();
System.out.println(a.getpro());
}
That's entirely unrelated to the processor instance you've created in your main method. If your kasir class should logically "know about" the other processor instance, you probably want a processor field in the class, which you might populate via the constructor - so your main method might become:
public static void main(String[] args) {
processor a = new processor();
a.daftarpro();
kasir x = new kasir(a);
x.semua();
}
As an aside, you should really try to follow the Java naming conventions, so classes of Processor and Kasir, and methods of getPro etc. (And if your code actually looks like that in your editor, I suggest you reformat it, too...)

Can a JUnit testmethod have a argument?

import java.util.regex.Pattern;
public class TestUI {
private static Pattern p = Pattern.compile("^[A-Za-z0-9()+-]+$");
public static void main(String[] args) {
// Test case1
String[] str=test();
System.out.println(str[0]+str.length);
match("Alphanumeric(Text)");
}
private static String[] test() {
boolean res;
String[] array={"a","b","c","d","e"};
for(int i=0;i<array.length;i++){
System.out.println(match(array[i]));
res=match(array[i]);
if(res=true)
calltomethod(array);
}
return array;
}
private static boolean match(String s) {
return p.matcher(s).matches();
}
}
In the above code I need to pass the array as a argument to a JUnit method, the above code will be present in a JUnit class, can I have these kind of methods in a JUnit class and a test =method with argument?
You should take a look at parameterized unit tests (introduced in JUnit 4).
Daniel Mayer's blog has an example of this.
Another, more simple example is on mkyong's webpage
Yes you can with the Theories Runner in JUnit 4.4
#RunWith(Theories.class)
public class TheorieTest {
#DataPoints
public static String[] strings={"a","b","c","d","e"};
private static Pattern p = Pattern.compile("^[A-Za-z0-9()+-]+$");
#Theory
public void stringTest(String x) {
assertTrue("string " + x + " should match but does not", p.matcher(x).matches());
}
}
For more details:
Junit 4.4 Release Notes
Blog
yes, it can. recently i started zohhak project. it lets you write:
#TestWith({
"25 USD",
"38 GBP",
"null"
})
public void testMethod(Money money) {
...
}
You can't directly pass parameters to test methods with JUnit. TestNG allows it, though:
//This method will provide data to any test method that declares that its Data
// Provider is named "test1"
#DataProvider(name = "test1")
public Object[][] createData1() {
return new Object[][] {
{ "Cedric", new Integer(36) },
{ "Anne", new Integer(37)},
};
}
//This test method declares that its data should be supplied by the Data Provider
//named "test1"
#Test(dataProvider = "test1")
public void verifyData1(String n1, Integer n2) {
System.out.println(n1 + " " + n2);
}
will print:
Cedric 36
Anne 37

Categories

Resources