I have a class which I would like to test.Whenever possible I would do dependency injections for that class which depends on object of other classes.But,I ran into a case where I would like to mock the object without restructuring the code and not appling DI.
Here is the class under test:
public class Dealer {
public int show(CarListClass car){
Print print=new Print();
List<String> list=new LinkedList<String>();
list=car.getList();
System.out.println("Size of car list :"+list.size());
int printedLines=car.printDelegate(print);
System.out.println("Num of lines printed"+printedLines);
return num;
}
}
and my test class for this is:
public class Tester {
Dealer dealer;
CarListClass car=mock(CarListClass.class);
List<String> carTest;
Print print=mock(Print.class);
#Before
public void setUp() throws Exception {
dealer=new Dealer();
carTest=new LinkedList<String>();
carTest.add("FORD-Mustang");
when(car.getList()).thenReturn(carTest);
when(car.printDelegate(print)).thenReturn(9);
}
#Test
public void test() {
int no=dealer.show(car);
assertEquals(2,number);//not worried about assert as of now
}
}
I couldn't figure out a solution to mock the print object inside the Dealer class.Since,I mock it in the Test class,but it gets created in the method under test.I did my research,but couldn't find any good resource.
I know taking Print object creation out of this method and Injection the object is the better way,but I would like to test the code as it is ,with the print object being created inside the method.Is there any way to do this
If you just want to mock the return value of car.printDelegate(), how about mock any Print instance for the call?
when(car.printDelegate(org.mockito.Matchers.any(Print.class))).thenReturn(9);
By the way, I'm confusing about your following code:-
List<String> list=new LinkedList<String>(); // allocate a empty list worth
list=car.getList(); // nothing but wasting memory.
...
return num; // no definition, do you mean printedLines?
Related
I am trying to improve my knowledge about testing I'm trying to achieve running the same JUnit test class with different objects derived from the same interface.
so we can assume the following:
interface Base {
void sort();
}
class A implements Base {
#Override
public void sort() {
//sort naively
}
}
class B implements Base {
#Override
public void sort() {
//sort using another better approach
}
}
class C implements Base {
#Override
public void sort() {
//sort using optimized approach
}
}
class Test {
#Test
void test1() {
Base obj = new A();
obj.sort();
obj.otherStuff();
}
}
class SecondTest {
//trying to avoid making multiple test classes that has only one line in difference
#Test
void test1() {
var obj = new B();
obj.sort();
obj.otherStuff();
}
So my question is how to run the test class with the objects from A,B,C without falling into the trap of duplicate code and redundancy?
Please note that I wrote this example just to illustrate my point, and the sort() doStuff() methods are just placeholders but when you have over ~70 line of code duplication in each test class it starts to look ugly and redundant.
*I have looked at #beforeEach, #Before, #After and I don't think I see a way where those might help me.
You can write a parameterized test with a MethodSource.
#ParameterizedTest
#MethodSource("bases")
void test1(Base obj) {
obj.sort();
obj.otherStuff();
}
static Stream<String> bases() {
return Stream.of(new A(), new B(), new C());
}
A way to fix it is the following, you create a method within your test class that takes as input the Base obj and contains all the duplicate lines. What you'll do then is to initialize the obj in different tests, then pass it to the method.
Here is a code that would do the job:
class Test {
#Test
void test1() {
Base obj = new A();
wrapperMethod(obj);
}
#Test
void test2() {
var obj = new B();
wrapperMethod(obj);
}
public static void wrapperMethod(Base obj){
obj.sort();
obj.otherStuff();
}
}
As a rule of thumb, testing can be much like normal programming where redundancy is avoided with methods to guarantee reusability.
Cheers,
D
First of all you have to fix your understanding of what UnitTesting is about.
UnitTesting is not about code (coverage).
UnitTesing is about verifying desired public behavior where "public behavior means return values and/or communication with dependencies.
Each test method should verify a single atomic assumption of the tested units desired behavior.
From this point of view it does not make sense to pass a bunch of objects sharing the same interface trough the same test method since these different interface implementations exist to implements the interfaces methods with their own unique behavior. In turn the assumption how the objects behave differ uniquely.
If all the objects where expected to behave identically (which is the only assumption a single test method could verify) there where no different objects (i.e. implementations) in the first place.
I have just started learning JUnit very recently and came across the following problem.
Have a look at the following class
class MyClass {
String a;
public MyClass(String a) {
this.a=a;
String doSomething(String a) {
if( a.isEmpty() )
return "isEmpty";
else
return"isNotEmpty";
}
I want to test the above method for both the conditions. If I proceed with the general structure of writing testcases it will look something like this:
class MyClassTest {
MyClass myClass;
#BeforeEach
void setUp() {
myClass=new MyClass("sampleString");
}
#Test
void doSomethingTest() {
Assertions.equal("isNotEmpty", myClass.doSomething());
}
}
However, for testing the empty string condition I will need another setup method where instead of "sampleString" I pass an empty string.
Following are the approaches I could think of and the questions for each:
Not use setUp at all and instead initialize the class in the individual test method. However, if let's say there are 10 testcases; 5 of which require empty string and rest "sampleString" then this doesn't make sense. Again, we can have a separate method for this repetitive code and call it individually in each testcase but then that defeats the purpose of having a steup method. Lets say I wanted to use two different setup methods, is there a way to do so?
Have a parameterized setup. I don't know if this is possible though. If yes, please share some useful links for this.
Use TestFactory. I tried reading up about this, but couldn't find an example for this specific case. If you have any, please share.
This example has been kept simple for illustrative purposes.
Group the tests with the same setup in an inner class annotated with #Nested. Each nested test class can have its own setup in a local #BeforeEach method.
You can always prepare the non-common data inside your test method. I've always thought it's easier this way, compared to using parameterized tests. You can't mix parameterized and non-parameterized tests in 1 file.
#Test
void doSomething_nullString()
{
myClass = new MyClass(null);
Assert.assertNull(myClass.doSomething());
}
#Test
void doSomething_emptyString()
{
myClass = new MyClass("");
Assert.assertEquals("", myClass.doSomething());
}
#Test
void doSomething_nonEmptyString()
{
myClass = new MyClass("sampleString");
Assert.assertEquals("sampleString", myClass.doSomething());
}
Or, you can always have helper methods inside the test class.
private MyClass createTestObject_nonNullString() {
return new MyClass("nonNullString");
}
private MyClass createTestObject_nullString() {
return new MyClass(null);
}
#Test
public void doSomething_sample() {
MyClass test = createTestObject_nonNullString();
// perform test
}
For Example there is a class A with two methods methodUnderTest() and display() where methodUnderTest calls the display method. While writing a junit using mockito how can I mock the display() method?
class A{
public int method methodUnderTest{
//some code
display();
}
public int display(){
//some code
}
}
If this is your class:
public static class A{
public int methodUnderTest() {
return display();
}
public int display(){
return 1;
}
}
then using mockito, you can do this:
A a = spy(new A());
when(a.display()).thenReturn(0);
System.out.println(a.methodUnderTest()); // will print 0
Explanation:
When you mock() a class, there is no underlying instance, and all the methods you call will do nothing and return default values unless specified otherwise.
When you spy() on an instance, all calls get recorded, and forwarded to the actual instance. This means that your class behaviour will stay exactly the same unless you mock a specific call.
Having said that, a case like yours is usually a symptom that you need to split the class, and invest a bit in separating your concerns.
You don't need mockito for it. In the test when you create your test object you can create it by
A underTest = new A() {
#Override
public int display() {
return <expected result>
}
}
In this way you can control what kind of value is returned by the display method.
If you want to use mockito, I'd go for something like that :
#Mock
private A a;
#Test
public void test() {
//define the behaviour
Mockito.when(a.display()).thenReturn(12);
// call methodUnderTest
int res = a.methodUnderTest();
// check that you get what you want
Assert.assertEquals(SOME_VALUE, res);
}
And if you don't want to use annotations, you'd initialize a like this :
A a = Mockito.spy(new A());
HTH!
I came across the following issue when I was trying to unit test my code. If I have a class that creates an instance and for example a getter method like this:
public class Test {
private static Test instance;
private ArrayList<String> arrayList = new ArrayList<String>();
public static Test getInstance() {
return instance;
}
private ArrayList<String> getArrayList() {
return arrayList;
}
}
If now I want to access the arrayList in a test case it would fail, because the list is returned by a non-accessable private method. So trying something like this wouldn't work:
public class AccessTest {
private Test test;
public void accessList(){
test = Test.getInstance();
test.getArrayList();
}
}
So one way to access the arrayList anyway, would probably be to change the visibility to protected. But isn't there a better way to access the method? Is it really necessary to make a method protected only because of a test that needs to access it?
In general, if you have some private methods in your class and you feel that you have problems with testing them, it is a sign of a bit of a code smell. It shows that too many functionality is hidden behind private wall.
You could change visibility of such method to package protected, so JUnit test will see it. There is also a Google Guava annotation #VisibleForTesting or something like that. But again - this is a sign of wrong class design.
Think of extracting such method to a separate class and make that methods public then.
For example, take a look at the following code:
class ReportCreator {
public File createSomeImportantReport(LocalDate date) {
String fileName = provideFileName(date);
File result = new File(fileName);
return result;
}
private String provideFileName(LocalDate date) {
// ... some complex business logic to generate file name based on date... ;)
return fileName;
}
}
There is a private method provideFileName() that does some complicated things and let's say it's hard to test if you would test only createSomeImportantReport().
See what changes if you externalize that functionality.
class ReportCreator {
private FileNameProvider fileNameProvider;
public File createSomeImportantReport(LocalDate date) {
File result = new File(fileNameProvider.provideFileName(date));
return result;
}
}
class FileNameProvider {
public String provideFileName(LocalDate date) {
return ......;
}
}
You now have option to test that thing separately, focus on what's important in that particular case.
Despite the fact that I don't see a use case for a private getter, you can use the package private access level. This is the default access level so you don't have to specify it. You can then test it by adding the test class in the same package name in the test directory. For instance the class is located in src/main/java/application and the test class can then be located in src/test/java/application.
Use Java Reflection for that:
Test test = new Test();
Method getArrayListMethod = test.getClass().getDeclaredMethod("getArrayList", null);
getArrayListMethod.setAccessible(true);
ArrayList<String> list = (ArrayList<String>) getArrayListMethod .invoke(test);
System.out.println(list); // Prints the list
Create your Test object, use the method getClass() and get the method declared on that class by its name.
Then set that method accessible dynamically. If you know the data type that it returns, then cast it to it.
I have a simple class, that contains a list:
public class SomeClass {
private AppDataSource appDataSource; // it's interface
private List<Object> someList;
////
public List<Obejct> loadSomeList() {
if (someList == null) {
return appDataSource.getListFromDatabase();
}
retrunf someList;
}
}
The point is - i want that list to be loaded from DB only once. And i want to unit test this function. I am noob in TDD and all i could do - write a public getter and setter for someList and use them in unit test. But it's conceptually wrong - i don't want class's clients use this member variable directlty.
How can i properly test method in this situation?
You are getting unit testing wrong.
Unit testing is about testing behavior of your classes; not implementation details.
You don't test if private fields do have this or that content. The only thing you test is that methods do what they are supposed to do.
That of course means that your class must have ways to insert "special lists" for testing.
Long story short: you want to step back, and spent the next 2, 3 hours
learning how to write "easy to test code"; for example by watching the great videos from Google Tech on CleanCode .
You should mock your list before your tests are coming.Use #Before for initialize your list.
private List<Object> someList;
#Before
public void initialize() {
someList = new ArrayList<Object>();
someLisi.add(..);
someList.add(..);
}
And test your method using this mock list.You can also use #BeforeClass for mocking your list. You can read differences between #Before and #BeforeClass here
Rather than exposing and testing the list, change your appDataSource so that you can set it from outside of the class. Make it an interface that provides the getListFromDatabase() method. Then for testing, pass in a mock datasource that implements the interface and has a counter that you can query to tell you how many times the getListFromDatabase method was called.
Look at what you want to test, and then work towards that. You didn't mention in your criteria that the list itself was important. What was important was how many times you query the database.
If you create a package in the test directory with the same name of the package of your class, and if you put the field in protected you will be able to access the field directly
You could initialize your private fields through constructor in test fixture. It's the most common way I guess.
Another option is to write tests in Groovy which can directly access private fields in Java classes. So you don't need to give an access to your private fields.
You are able to test your loadSomeList() like this:
public class SomeClass {
private List<Object> someList;
public List<Object> loadSomeList() {
if (someList == null) {
someList = new ArrayList<>();
someList.add(new Object());
return someList;
}
return someList;
}
public List<Object> getSomeList() {
return someList;
}
public void setSomeList(List<Object> someList) {
this.someList = someList;
}
The Test Class should have two tests:
In the first test you can test if you have a new List. Your create a
new instance of SomeClass and call your someClass.loadSomeList()
method. If the list is not null the test is ok.
The second test you can test if your someClass instance already has a list. In the test your just add one object in your list and set it to someClass.
public class SomeClassTest {
#Test
public void testLoadSomeListNewList() {
SomeClass someClass = new SomeClass();
List<Object> list = someClass.loadSomeList();
assertNotNull(list);
}
#Test
public void testLoadSomeListGivenList() {
SomeClass someClass = new SomeClass();
List<Object> list = new ArrayList<>();
list.add(new Object());
someClass.setSomeList(list);
someClass.loadSomeList();
assertTrue(someClass.getSomeList().size() == 1);
}