As a homework exercise (I'm a beginner) I had to write a Java program which accesses a database (PostgreSQL). The program can, e.g., insert new users, increment some fields etc. and I have methods such as: addUser(User t), deleteUser(User t) and so on.
I also have written test methods using junit5. For the tests I use a 'test' database, separate from the 'work' one. The coordinates to open the two databases (database name, password etc.) are stored in two files called config.properties and config.test.properties, which are selected at runtime.
What I have in place now is something along these lines, using a boolean flag variable:
public class UserDao {
public boolean isTestMode = false;
public Connection getConnection() {
if (this.isTestMode) {
input = cl.getResourceAsStream("config.test.properties");
} else {
input = cl.getResourceAsStream("config.properties");
}
...
}
}
In my test methods I then set the flag like this:
void testAddUser() {
UserDao dao = new UserDao();
dao.isTestMode = true;
...
}
In regular, non-test method I don't set isTestMode, which therefore stays to its default (false) value and config.properties is used.
My approach works, but my instructor told me it is bad practice to do things like this and I should change it, for example (he suggested) doing a dependency injection. I'm not too sure how to proceed.
I could make configFilename a class variable and add to the class UserDao a new constructor which accepts a filename, like this:
public class UserDao {
private String configFilename = "config.properties";
public UserDao() {
}
public UserDao(String filename) {
this();
this.configFilename = filename;
}
public Connection getConnection() {
input = cl.getResourceAsStream(this.configFilename);
...
}
}
Then in the test methods I use the new construtor UserDao("config.test.properties")
A (in my view a better) variant is to introduce a constructor which accepts a boolean isTestMode and sets configFilename accordingly (I don't need nor want the flexibility of specifying any filename in the constructor). But essentially this is the same as my original approach, which I was told to change. Also, there no dependency injection there... what is it best practice in such cases? Any suggestion would be welcome!
Passing parameter can be seen as a trivial dependency injection.
Concerning your java: when you set a default value for configFilename, you can see that as a convention that you use in your application.
Your class does not need that. And if you avoid this convention, you got immutability for free. For example, you can do :
public class UserDao {
private final String configFilename;
public UserDao(String filename) {
this.configFilename = filename;
}
public Connection getConnection() {
input = cl.getResourceAsStream(this.configFilename);
...
}
}
UserDao can be used by your test classes or your main classes the same way.
With your solution, you may deliver code that will never run in production (the branch where isTestMode is true), and that's not a good practice. This code could be seen as dead code in production.
In application use default constructor when creating an instance of UserDao, in junit pass name of file:
new UserDao("config.test.properties");
private final String configFilename;
public UserDao() {
this("config.properties");
}
public UserDao(String filename) {
this.configFilename = filename;
}
Related
I have a Java class like the following:
public class MyClass {
/** Database Connection. */
private dbCon;
public MyClass() {
dbCon = ...
}
public void doSomethingWith(MyData data) {
data = convertData(data);
dbCon.storeData(data);
}
private MyData convertData(MyData data) {
// Some complex logic...
return data;
}
}
since the true logic of this class lies in the convertData() method, I want to write a Unit Test for this method.
So I read this post
How do I test a private function or a class that has private methods, fields or inner classes?
where a lot of people say that the need to test a private method is a design smell. How can it be done better?
I see 2 approaches:
Extract the convertData() method into some utility class with a public api. But I think this would be also bad practice since such utility classes will violate the single responsibilty principle, unless I create a lot of utility classes with maybe only one or two methods.
Write a second constructor that allows injection of the dbCon, which allows me to inject a mocked version of the database connection and run my test against the public doSomething() method. This would be my preferred approach, but there are also discussions about how the need of mocking is also a code smell.
Are there any best practices regarding this problem?
Extract the convertData() method into some utility class with a public api. But I think this would be also bad practice since such utility classes will violate the single responsibility principle, unless I create a lot of utility classes with maybe only one or two methods.
You interpretation of this is wrong. That is exactly what the SRP and SoC (Separation of Concerns) suggests
public interface MyDataConverter {
MyData convertData(MyData data);
}
public class MyDataConverterImplementation implements MyDataConverter {
public MyData convertData(MyData data) {
// Some complex logic...
return data;
}
}
convertData implementation can be now tested in isolation and independent of MyClass
Write a second constructor that allows injection of the dbCon, which allows me to inject a mocked version of the database connection and run my test against the public doSomething() method. This would be my preferred approach, but there are also discussions about how the need of mocking is also a code smell.
Wrong again. Research Explicit Dependency Principle.
public class MyClass {
private DbConnection dbCon;
private MyDataConverter converter;
public MyClass(DbConnection dbCon, MyDataConverter converter) {
this.dbCon = dbCon;
this.converter = converter;
}
public void doSomethingWith(MyData data) {
data = converter.convertData(data);
dbCon.storeData(data);
}
}
MyClass is now more honest about what it needs to perform its desired function.
It can also be unit tested in isolation with the injection of mocked dependencies.
I have 4 step definition classes and a set of domain object classes.
My first step definition class looks like this:
public class ClaimProcessSteps {
Claim claim;
public ClaimProcessSteps(Claim w){
this.claim = w;
}
#Given("^a claim submitted with different enrolled phone's model$")
public void aClaimSubmittedFromCLIENTSChannelWithDifferentEnrolledPhoneSModel() throws Throwable {
claim = ObjMotherClaim.aClaimWithAssetIVH();
}
}
My Claim class looks like this:
public class Claim {
private String claimType;
private String clientName;
private Customer caller;
private List<Hold> holds;
public Claim() {}
public Claim(String claimType, String clientName, Customer caller) {
this.claimType = claimType;
this.clientName = clientName;
this.caller = caller;
}
public String getClaimType() {
return claimType;
}
My second step definition class looks like:
public class CaseLookupSteps {
Claim claim;
public CaseLookupSteps(Claim w){
this.claim = w;
}
#When("^I access case via (right|left) search$")
public void iAccessCaseInCompassViaRightSearch(String searchVia) throws Throwable {
System.out.println(claim.getClaimType());
}
I've already imported the picocontainter dependency in my POM.XML and I am getting the following error.
3 satisfiable constructors is too many for 'class java.lang.String'. Constructor List:[(Buffer), (Builder), ()]
None of my step definition classes constructors receive primitives as arguments. Does anyone have any clue as to why I am still getting that error? Could it be my business object constructor that does expect a String in its constructor?
Thanks in advance for any help.
Picocontainer looks over not only your step definition classes to resolve dependencies. It also looks over all classes that your steps definitions depend on.
In this case, it's trying to resolve the dependencies for your non-default Claim constructor.
public Claim(String claimType, String clientName, Customer caller) {
...
}
According to this issue there's no way to solve this other than keeping only default constructors in all your dependencies.
Assuming your scenario looks like this:
Given some sort of claim
When I lookup this claim
Then I see this claim
Currently your test is missing the setup step of the claim.
So rather then directly sharing the claim object between steps you should create a ClaimService class with only the default constructor. You can inject this service into your step definitions.
Once you have injected the service, you can use it in the step definition of Given some sort of claim to callclaimService.createSomeSortOfClaim() to create a claim. This claim can be created in memory, in a mock db, actual db, or other persistence medium.
In When I lookup this claim you then use claimService.getClaim() to return that claim so you can use its type to search for it.
Doing it this way you'll avoid the difficulty of trying to make the DI container figure out how it should create the claim under test.
I'm trying to mock the following class which contains some static members
public class ClientFact {
private static final String BASE_URL = Config.getProperty("prop1");
private static final String USERID = Config.getProperty("prop2");
......................
public static Client createClient() throws AppException {
}
}
but i'm running into issues with the static member variables which are populated by Config.getProperty. This class does a read on a properties file like so
public class Config {
...............
public static String getProperty(Param param) {
String value = null;
if (param != null) {
value = properties.getProperty(param.toString());
}
return value;
}
}
I'm trying to mock this call since i dont care about the loaded properties in my test. This is what ive tried
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClientFact.class})
public class MyTests {
#Test
public void test() {
PowerMock.mockStaticPartial(Config.class, "getProperty");
EasyMock.expect(Config.getProperty(EasyMock.anyObject())).andReturn(EasyMock.anyString()).anyTimes();
PowerMock.mockStatic(ClientFact.class);
}
}
but its giving the following error...
java.lang.NoSuchMethodError: org/easymock/internal/MocksControl.createMock(Ljava/lang/Class;[Ljava/lang/reflect/Method;)Ljava/lang/Object;
at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:2214)
at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2163)
any ideas what im doign wrong here?
A non-answer: consider not making static calls there.
You see, that directly couples that one class to the implementation of that static method in some other class; for no real reason. (and for the record: it seems strange that a USER_ID String is a static field in your ClientFact class. Do you really intend that all ClientFacts are using the same USER_ID?!)
You could replace that static call with a non-static version (for example by introducing an interface); and then you can use dependency injection to make an instance of that interface available to your class under test. And then all your testing works without the need to Powermock.
Long story short: very often (but not always!) the need to turn to Powermock originates in production code which wasn't written to be testable (like in your case). Thus instead of using the big bad Powermock hammer to "fix" your testing problem, you should consider improving your production code.
You might want to listen to those videos to get a better understanding what I am talking about.
I have this beautiful scenery in front of me including JSF, jUnit(4.11) and Mockito(1.10.19):
#ManagedBean
#ViewScoped
public class UserAuth implements Serializable {
private List<UserRole> roleList;
private LocalChangeBean localChangeBean;
public UserAuth() {
roleList = new ArrayList<UserRole>();
localChangeBean = (LocalChangeBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("localChangeBean");
setLocalChangeBean(localChangeBean);
setRoleList(getLocalChangeBean().getRoleList());
//many other property setting and some JSF stuff
}
public boolean checkAuth() {
for (UserRole role : getRoleList()) {
if(role.getName().equals("SUPER_USER"))
return true;
}
return false;
}
}
//A hell of a lot more code, proper getters/setters etc.
Here is the test class:
public class UserAuthTest {
#Test
public void testCheckAuth() {
UserAuth bean = mock(UserAuth.class);
List<UserRole> mockRoleList = new ArrayList<UserRole>();
UserRole ur = mock(UserRole.class);
when(ur.getName()).thenReturn("SUPER_USER");
mockRoleList.add(ur);
when(bean.getRoleList()).thenReturn(mockRoleList);
assertEquals(true, bean.checkAuth());
}
The thing is; UserRole class is not reachable by me, it's another part of the project. It doesn't have a no-argument constructor and the existing constructor requires other unreachable classes etc. Thus I can't instantiate it. In these circumstances, all I want to do is to make that mock UserRole object behave such as returning the needed String when it's getName() method gets called.
But obviously; when I try to add that UserRole mock object into the List of UserRoles, the behavior that I tried to define is not stored with the object. And yes, the code looks pretty funny in its current stance. Though I left it there to learn what should I do to achieve this simple, little goal of mine.
Post-Edit:
I couldn't manage the problem without changing the original bean, though I followed Jeff's suggestion below and it worked well as a strategy of isolation. I did not mark it as the best answer since the question was "How to mock an unreachable third party class?" (in the current example its the UserRole class) Eventually the noob me understood that "Mocking an unreachable third party class is no different than mocking any other class".
Here is how I managed it:
#ManagedBean
#ViewScoped
public class UserAuth implements Serializable {
private List<UserRole> roleList;
private LocalChangeBean localChangeBean;
public UserAuth() {
//the actual constructor including all JSF logic, highly dependent
}
UserAuth(List<UserRole> roleList) {
setRoleList(roleList);
//package private test-helper constructor which has no dependency on FacesContext etc.
}
public boolean checkAuth() {
for (UserRole role : getRoleList()) {
if(role.getName().equals("SUPER_USER"))
return true;
}
return false;
}
}
And here is the test class (attention to the iterator mock, it has the whole trick):
public class UserAuthTest {
private UserRole mockRole;
private Iterator<UserRole> roleIterator;
private List<UserRole> mockRoleList;
private UserAuth tester;
#SuppressWarnings("unchecked")
#Before
public void setup() {
mockRoleList = mock(List.class);
mockRole = mock(UserRole.class);
roleIterator = mock(Iterator.class);
when(mockRoleList.iterator()).thenReturn(roleIterator);
when(roleIterator.hasNext()).thenReturn(true, false);
when(roleIterator.next()).thenReturn(mockRole);
tester = new UserAuth(mockRoleList);
}
#Test
public void testCheckAuth(){
when(mockRole.getName()).thenReturn("SUPER_USER");
assertEquals("SUPER_USER expected: ", true, tester.checkAuth());
}
You don't need Mockito. A quick refactor will do this for you.
Your problem: Your code relies on a static call to FacesContext.getCurrentInstance() in your constructor, that is difficult to prepare or substitute out in tests.
Your proposed solution: Use Mockito to substitute out the FacesContext instance, the external context, or the session map. This is partly tricky because Mockito works by proxying out the instances, so without PowerMock you won't be able to replace the static call, and without a way to insert the mock into FacesContext or its tree, you have no alternative.
My proposed solution: Break out the bad call FacesContext.getCurrentInstance().getExternalContext.getSessionMap() into the default constructor. Don't call that constructor from tests; assume it works in the unit testing case. Instead, write a constructor that takes in the session map as a Map<String, Object>, and call that constructor from your tests. That gives you the best ability to test your own logic.
#ManagedBean
#ViewScoped
public class UserAuth implements Serializable {
// [snip]
public UserAuth() {
// For the public default constructor, use Faces and delegate to the
// package-private constructor.
this(FacesContext.getCurrentInstance().getExternalContext().getSessionMap());
}
/** Visible for testing. Allows passing in an arbitrary map. */
UserAuth(Map<String, Object> sessionMap) {
roleList = new ArrayList<UserRole>();
localChangeBean = (LocalChangeBean) sessionMap.get("localChangeBean");
setLocalChangeBean(localChangeBean);
setRoleList(getLocalChangeBean().getRoleList());
// [snip]
}
}
p.s. Another solution is to actually get the session map within the test and insert the value you need, but you have to be careful there not to pollute your other tests by installing something into a static instance that may persist between tests.
I have the following situation. I have a class
A {
public void setProps() {
// setting propertis
makeSomeWeirdConfigs();
//setting another properties
}
private void makeSomeWeirdConfigs() {
// making configs
}
public Props getProps() {
//getting properties
}
}
Now I want to check with the help of JUnit test case if the properties are properly set by using method setProps() and then getting the properties with getProps().
The problem is this method makeSomeWeirdConfigs() in the middle of the setProps(), which when executed without the proper environment cause a lot of exceptions, so the props below this method are not set.
Also this method tries to do dangerous things for example executing some scripts etc. So my question is is it possible to skip this method makeSomeWeirdConfigs() somehow in the JUnit test case, so only setProps() and getProps() are executed.
The original class A should not be changed.
Thanks
"Original class should not be changed" - then you are seeking something mocking, byte code fiddling, AOP.
If you made makeSomeWeirdConfig protected, you could override the method and test a child class. The same with testing an extra flag.
If you could put the code in a delegator even better towards sound code.
class SomeWeirdConfig {
void makeSomeWeirdConfigs() { ... }
}
SomeWeirdConfig delegate = new SomeWeirdConfig();
public void initTest() { delegate = null; }
private void makeSomeWeirdConfigs() {
if (delegate != null) {
delegate.makeSomeWeirdConfigs();
}
}
Then the test could disable the setter.