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.
Related
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);
}
I have a Spring Controller class which has method defined which accepts private enum as below. How can we write test case for this using Junit/Mockito?
#RequestMapping("/getData")
public String getData(
#RequestParam(value = "someFilter") SomeFilter someFilter)
{
// do something
}
In above code, SomeFilter is an enum which is defined as a private inside class.
When writing test case for above method, as enum is not visible I cannot call the method, i tried of using Mockito.any(), still no use.
Do we have any way to test above method?
So, if the method will be called by spring, then you will have to find out, how and replicate that. But honestly, it still smells like horribly bad code, a public method that isn't actually public...
Anyway, you can of course test it via some reflection magic... Let's assume this simple class...
public class Testy {
private enum TestyEnum {
X,
y;
}
public String someMethod(final TestyEnum testyEnum) {
return testyEnum.name();
}
}
So, we have a private enum and a public method that accepts it as a paramter. To call it, we have to use reflection...
public class TestyTest {
private final Testy toTest = new Testy();
#Test
public void someMethod_should_return_correct_name_of_x() throws Exception {
// Get the class object for our private enum
final Class<?> testyEnumClass = Class.forName( "de.assona.iframe.view.Testy$TestyEnum" );
// List the enum constants
final Object[] consts = testyEnumClass.getEnumConstants();
// Get the method via reflection per name and argument type
final Method method = Testy.class.getMethod( "someMethod", testyEnumClass );
// call (invoke) it...
final Object o = method.invoke( this.toTest, consts[0] );
// And check that the object returned is actually the correct String we expect the name of the private enum constant)
Assert.assertEquals( "X", o );
}
}
But of course, this is a horrible workaround, bad to read, bad to maintain and the solution for a problem you should not have. Spring does not require you to produce bad code, on the contrary, it solves many problems that lead to bad code. So I would really suggest you try to refactor that code to make it testable in a clear, easily maintainable way. Trust me, you (and your fellow codes) will not be happy that you found a way to test bad code, since that makes you keep that bad code. Tested bad code is better than untested bad code, but still bad. You (and your fellow codes) will be much happier in the long run with good code, because it makes everything so much easier...
Instead of calling the method of the controller object, you could test your code with Spring MockMvc.
public class ControllerTest {
private final YourController controller = ...
private final MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller)
.build();
#Test
public void someTest() throws Exception {
mockMvc.perform(get("/getData").param("someFilter", "THE_NAME_OF_THE_FILTER"))
.andExpect(status().isOk())
.andExpect(content().mimeType("text/html"))
.andExpect(...);
}
}
I'll just start by saying that I am a new to Java programming. I've got this problem:
I have this class:
public class Unit
{
public boolean status;
public Unit()
{
status=true;
}
public boolean getstatus(){
return status;
}
public void setstatus(boolean pStatus){
status=pStatus;
}
}
And i need a second class called TestUnit that, when i use it to create a object, unpon creation it creates also a Unit class.
How can i do this? Help would be appreciated.
P.S.: I'm working with Bluej.
If your TestUnit class is in the same package, then it can just create a new Unit instance like this:
Unit u = new Unit();
But they ought really to be in different packages, for instance
com.giaky.unit
com.giaky.unit.test
In that case, you need to import the class into your TestUnit class. You do that with a line at the top of the file, just under the package statement, like this:
import com.giaky.unit.Unit;
After that, you can create instances of your Unit class just as if it were in the same package, with
Unit u = new Unit();
Your IDE will help you with all of this: it should be able to help you move the classes to different packages, if needed, and also to import classes from one package into another.
Importing is something you'll need a lot, every time you use a class from the JDK libraries.
Are you look for this?
public class TestUnit{
private Unit unit;
public TestUnit(){
unit = new Unit();
}
}
public class TestUnit{
private Unit unit;
public TestUnit(){
this.unit=new Unit();}
}
}
//you can add other methods and variables as needed :)
You can do something like this:
public class TestUnit {
//You can create a reference to handle your Unit instance
private Unit myunit;
//Provide a constructor to assign a unit you create
public TestUnit(Unit myunit) {
this.myunit = myunit;
}
//Or provide a default constructor which instances a default one
public TestUnit() {
this.myunit = new Unit();
}
}
I think that is a way you can handle, I know very good answers will come, but this is my approach according to your description :)
Regards and happy coding :).
Is it possible to control the value of the global variable in the class that I test?
The global variable is used in a private method, so I use a public method (in the same class) to pass through it.
How can I say that mListValService != null?
public class Myclass {
//my global variable
private ListValServiceRemote listValService = null;
public String getCodeValeurRef(Long idValeur) {
return getListValService().getRlvCode(idValeur);
// I want 100% coverage on this method so i have to change the value
// of mListValService.
private ListValServiceRemote getListValService() {
if (listValService == null) {
listValService = ServiceGetter.getListValService();
}
return listValService;
}
ReflectionTestUtils from spring-test might be a solution to access the field value. You can also use plain old reflection, add getter/setter to the field or make the field protected and put the test in the same package as the tested class.
Sample test:
public class MyclassTest {
private MyClass myClass;
#Before
public void setup() {
this.myClass = new MyClass();
}
#Test
public void testGetListValServiceWhenFieldIsNull() {
assertNotNull(this.myClass.getListValService());
}
#Test
public void testGetListValServiceWhenFieldIsNotNull() {
final ListValServiceRemote lvsr = new ListValServiceRemote();
ReflectionTestUtils.setField(this.myClass, "listValService", lvsr);
assertSame(lvsr, this.myClass.getListValService());
}
}
First of all, seems you are not using IoC technique, and hence you have problems while unit testing the code.
Secondly, a private is the private, don't test it. Your code should be tested and covered only by using public methods. If some code is not reachable via public interface, then it is not reachable at all. Why do you want to test it then?
This particular code could be easily 100% covered if you just invoke getCodeValeurRef() twice. And also if you would have listValService == null, it will cause NullPointerException failing the test anyway, so an assert is not required.
You could expose the getListValService() method as package-private, then call it in a test. You can confirm the same value is returned each time:
#Test
public void sameListValTest() {
Myclass foo = // construct this somewhow
assertTrue(foo.getListValService() == foo.getListValService());
}
This will give you 100% coverage without fiddling with a private field.
Or you could just call getCodeValeurRef() twice in your test to achieve the same results. Anything that causes the getListValService() to execute twice will give you 100% coverage. Exposing it as package-private allows you to verify that you are re-using the same field, not creating one each time (if that's important).
In an effort to reduce my NCSS count of a class (~850), I have split all of the methods into their own classes and to make things easier, I extend an abstract class that holds all the helper functions.
AbstractMethod.class
public class AbstractMethod {
protected String requestWebPage(URL url) {
// download a webpage as a string
}
}
Example "account" subclass
public class AccountData extends AbstractMethod {
public String getAccount(String sessionId){
String webPage = requestWebPage("http://google.com/"+sessionId);
system.out.println(webPage);
return webPage;
}
}
I have approx 10 of these method classes and would like to only initialize them when one of the methods in the main/base class is called:
public class MyBaseClass() {
private static AccountData ad;
public MyBaseClass() {
ad = new AccountData(); // Is there a better way?
}
public String getAccount(String sessionId) {
return ad.getAccount(String sessionId);
}
}
I have tried to create an initialise function in the MyBaseClass class that accepts the subtype as a parameter and create an object based on it's class:
private void initAccount() {
if (ad == null) {
ad = new AccountData();
}
}
but it's ugly and I have to have one per sub-class.
So, what's the "correct" way to do this? Sometimes when the class is called, we will only use 1 or 2 of the methods, so I don't want to have to initialise all the sub-classes each time.
It would seem to me that what you really want is to use static methods rather than abstract helper classes, perhaps along with import static.
That way, the class(es) defining those methods would, as you wish, only be initialized once the methods are actually called.
You would also not limit your inheritence structure in general to where the methods happen to be defined.
That's assuming you don't use any instance data for those methods, of course; but from the looks of your sample code, it doesn't seem that way.
Instantiating classes in Java is cheap. If the classes are not doing anything substantial in their contructors then just do
public String getAccount(String sessionId) {
AccountData ad = new AccountData();
return ad.getAccount(String sessionId);
}
Don't optimize where it's not nessesary. Profile your code before. You might be suprised how wrong your assumtions are (I know I was many times).