Hello I'm writting junit test how can I test this method .. this is only part of this method :
public MyClass{
public void myMethod(){
List<myObject> list = readData();
}
}
How will I make the test for this? ReadData is a private method inside MyClass?
You can always test the List object to see if it contains all of the elements that readData() is supposed to insert into the list. Make a public method that returns the list and you can compare the length and elements in that list to what you are expecting to be in there.
As written, it doesn't make sense to test myMethod() unless readData() changes the instance state the way Frank Grimm mentioned. One thing to do would be to change myMethod() so that it puts list into a List instance variable. Then you might do something like this:
#Test
public void testThatReadDataReturnsACorrectList(){
MyClass inst = new MyClass(); // Add args to ctor call if needed - maybe a file path that readData() will use?
inst.myMethod();
// Create a list of MyClasses that match what you expect readData() to return:
List<MyClass> expectedList = new List<>();
expectedList.Add(new MyClass(/* Some arguments */));
expectedList.Add(new MyClass(/* Some more arguments */));
expectedList.Add(new MyClass(/* Some other arguments */));
// Assert that the list you created matches the list you get back from
assertArrayEquals("Did not get the list expected", expectedList.ToArray(), inst.getList().ToArray());
}
You'd still have to write MyClass.getList() to return the List instance variable.
To be robust, you could make the MyClass constructor accept an object that implements an interface like IMyReadInterface. readData() would use that object. Then in your test, you could instantiate a mock that also implements IMyReadInterface, configure the mock to provide the data needed so that readData() works correctly, and construct inst with that mock.
Unless we know more about the method, all you really need to test is that the return from readData is in a format that fits into your generic list. Otherwise, its hard to recommend anything without knowing more about whats going on in your private method.
Related
I've faced this situation pretty often and don't know how to resolve it using Mockito's default methods such as (any, anyList, eq)
For example I have an object where I want to mock a method expecting a list which contains other mocked objects. Let me explain:
public class MyMapper {
public List<DataObjects> convertList(List<String> rawContents) {
rawContents.stream().map(r -> convertObject(r))
.collect(Collectors.toList());
}
public DataObject convertObject(String rawContent) {
return new DataObject(rawContent);
}
}
public class MyWorkerClass {
public boolean start(List<String> rawContents) {
List<DataObject> objects = new MyMapper().convertList(rawContents);
return publish(objects);
}
public boolean result publish(List<DataObject> objects) {
../// some logic
}
}
Now what I want to assert is something like. Note: Please assume the right mocks are returned when new() is called [Using some PowerMockito]
#Test
public void test() {
String content = "content";
DataObject mock1 = Mockito.mock(DataObject.class);
MyMapper mapperMock = Mockito.mock(MyMapper.class);
MyWorkerClass worker = new MyWorkerClass();
Mockito.when(mapperMock.convertObject(content)).thenReturn(mock1);
Mockito.when(worker.publish(eq(Arrays.asList(mock1)).thenReturn(true);
boolean result = worker.start(Arrays.asList(content));
Assert.assertTrue(result);
}
The problem with the code above is in the line
Mockito.when(worker.publish(eq(Arrays.asList(mock1)).thenReturn(true);
This will try to match the list object instead of the list contents, in other words, even when I have to lists A: [mock1] and B: [mock1], A is not equal to B and ultimately the stubbing fails.
What I need is some sort of matcher similar to hamcrest's contain matcher. Something like:
Mockito.when(worker.publish(contains(mock1)).thenReturn(true));
Is there anyway I can achieve this? Keep in mind the code above is just an example to grasp the problem, the real situation is a little bit more complex and I can only mock individual objects, not the list itself
Thanks
Nevermind, later I learned that Mockito's eq() method will call the equals() method on the argument. Now if that is an ArrayList it means it will return true if two list sizes are equal and if the equal's comparison for each one of the elements in the list also returns true. See https://docs.oracle.com/javase/6/docs/api/java/util/List.html#equals%28java.lang.Object%29
And for even more customization argThat() could be used What's the difference between Mockito Matchers isA, any, eq, and same?
public List<Object> getDummyData(String testString ) {
final List<String> result1 = utility.getData(testString);
final List<String> result2 = utility.getData(result1.get(0).split(~)[0]);
// Processing of result2 and few more method calls
return someListOfObject;
}
I need to mock the method having above method calls. When I go with below code:
MainApp mock= Mockito.mock(MainApp.class);
List<String> mockList = Mockito.mock(ArrayList.class);
doReturn(mockList).when(mock).getData("str");
I am getting IndexOutOfBoundsException while running the test case at second method call.
The reason for that exception is that line:
utility.getData(result1.get(0).split(~)[0]);
You want to split on the result from your first call.
But you didn't specify anything about that mock! And when you don't specify anything, then mockito will just return dummy/empty/null data when methods are called on that mock.
And you don't have to. You absolutely do not mock a list object. You simply create a list that fits your test; like
List<String> dummyList = Arrays.asList("whatever", "strings", "you need");
Just to make that very clear: mocking is your last resort. You only use it in order to get control over objects you need to control; and that can't be controlled any other way.
And a list is super-easy to control: by creating a list that contains what you need to be in that list.
The other part of your question: you can instruct Mockito easily to return different results when the same method is called repeatedly; for example like shown here.
The reason you are getting an error is that Mockito.mock(ArrayList.class) has not values so when get(0) you get the IndexOutOfBoundsException.
Instead you should be putting data in a real list.
MainApp mock= Mockito.mock(MainApp.class);
List<String> resultA = Arrays.asList("some~value", "some~other~value");
doReturn(resultA).when(mock).getData("str");
List<String> resultB = Arrays.asList("other value", "more other values");
doReturn(resultB).when(mock).getData("some");
While the above would work I would suggest using matchers for the mocking and then verify the correct results. The reason being that you will get better error messages if the test fails.
MainApp mock= Mockito.mock(MainApp.class);
// Mock multiple return values
Mockito.when(mock.getData(anyString())
.thenReturn(Arrays.asList("some~value", "some~other~value"))
.thenReturn(Arrays.asList("other value", "more other values"));
List<SomeObjects> result = getDummyData("some-arg");
Mockito.verify(mock).getData("some-arg"); //Verify correct calls
Mockito.verify(mock).getData("some");
// verify result
I'm probably stumbling on weak OO bases but how can I load elegantly an arraylist of my custom object trough a function in my main program?
I'd like it to look like it from the main:
ArrayList<MyObject> mylist = new ArrayList<MyObject>();
mylist.FetchFromDb();
I can't figure what would be the right thing to do:
extending the ArrayList class seems bad
method in main passed with the arraylist as an argument seems ugly
method in MyObject class doesn't work since mylist is an instance of arraylist
Of course i would be making connection to db and iterating over my resultset in that function, which I have no problem with for a standard object.
If you want to have a list that has such method, you should create your own class
class MyList<T> {
private ArrayList<T> storage = new ArrayList<>();
public void fetchFromDb() {
// ...
}
}
However I think you should create a separate function that fills the list, as a list function is not to fetch data from a database, but to provide functionality to store and retrieve elements.
You can't achieve that in Java without extending ArrayList or (even uglier, using delegate objects).
Not to say you cannot do this but you are talking about adding a method FetchFromDb() to Java's ArrayList object.
What would seem more appropriate to do is add to your object a FetchFromDb() which returns a list of the MyObject and then initialize the ArrayList with that.
public class MyObject{
//...
public static ArrayList<Node> FetchFromDb(){
//Code to get all the objects and add them to a list
//Return the list
}
}
Then you can call the static method
ArrayList<MyObject> mylist = MyObject.FetchFromDb();
The other option is to use a DAO which others have suggested and you can read about here
When I add a member object from a class called Member to an array list "members = new ArrayList();" within a class called Library, and then try and print off a list of data within the array list I get an error message in the print out:
Member#12eb9b8
Member#172d568
The method I am using to add the member objects to the array list is:
public void joinMember(Member joinMember)
{
members.add(joinMember);
}
And the method I am using to print out all of the data within the array list is:
public void listMembers()
{
for(Member joinMember : members){
System.out.println(joinMember);
}
}
Can anyone please help? I have checked over the code and I cannot work out why it's not printing out the correct data.
What you're seeing is the Object implementation of the toString method. It's not an error. If you want it to print out something meaningful, you can override the toString method in the Member class.
Example
public String toString() {
// name is just an example. can be anything.
return this.name;
}
That is not an error, it seems to be the value of instantiated object references. If you want to print what is inside, you either need to access something from the object to print, like
object.getSomething(); // Assuming the getSomething() method prints something
// useful from within the class
or
Add a toString() method to the class.
It seems to be printing the correct data. The "problem" is that you are printing only the "object address". You should add some method in your Member class to print some information that you wish and use it in your "Sysout" method:
System.out.println(joinMember.getName());
Let me know if that's what you want.
I am writing a Linked List class that takes in names or numbers, and then prints them out in a list. I managed to write the list normally. Here is what I did:
public String toString(){
return list.toString; //where list is the LinkedList I am calling
}
That works correctly and returns my list after adding 4 elements like this:
[Joe, Jessica, Max, 5]
Now I am trying to convert that same method onto a generic method, so I did 2 things.
Here I created the collections object:
private Collection<E> collection;
public MyLinkedListG(Collection<E> _collection) {
collection= _collection;
}
And here is how I wrote the new toString in collections:
public String toString(){
StringBuilder builder = new StringBuilder();
for(E e : collection) {
builder.append(e); //appends each string
}
return builder.toString();
}
The problem is that now my test class will not allow me to call the LinkedList object I had created before which was:
MyLinkedListG x = new MyLinkedListG();
It states I need to input a collection inside the parameter. How can I call it now? Or am I doing it totally wrong?
If something is not clear please let me know so I can clarify as soon as possible. Thanks in advanced.
From what I can tell, your original class likely did not include a constructor. This means the no-arguments constructor new MyLinkedListG() is provided by default, which is likely what you used to construct an instance of your class.
After your modifications, you added a constructor MyLinkedListG(Collection<E> _collection). Now the no-arguments constructor is not provided by default anymore. If you want to continue to use it, it must be explicitly defined.
Your class will probably have two (or more) constructors in this case, perhaps something like this:
private Collection<E> collection;
public MyLinkedListG(Collection<E> _collection) {
collection= _collection;
}
public MyLinkedListG() {
collection=new LinkedList<E>();
}
Now you can use either constructor for your object.
You can only use an empty constructor if
A) you have not defined a constructor
or
B) if you have explicitly defined an empty constructor.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.8.9