I have a Predicate which checks for a row existence in Database.I am not sure if this is a good use of predicate but it made my code clean and concise.But when I am Tesing this code I am not able to mock the DAO class and not sure why is the case.
public class validator{
public Predicate<String> doesRowExists = fileName -> makeDao().isRowReturned(RowId);
public AlertFileDAO makeDataDao(){
return new DataDao();
}
public boolean validate(String RowId){
return doesRowExists.test(rowId)
}
}
//Test
public class ValidatorTest{
#setup
void beforeAll(){
mockValidator = spy(new Validator());
doReturn(mockDataDao)
.when(mockValidator)
.makeDataDao();
}
#Test
test_whenRowExists(){
new Validator.validate("1-abc-34");
}
When Im triggering the test it is hitting the actual DB and not using the mocked DAO class.Im not sure what exactly I am missing here.Please suggest.
Why don’t you simply inline the predicate and deliver the dao as constructor argument? This makes your api cleaner: method call vs getter for predicate and test on predicate you ended up with.
With your accepted answer, the user has to use the following:
validator.doesRowExist().test(rowId);
I believe the following would be easier to use:
validator.doesRowExist(rowId);
or even:
validator.validate(rowId);
Lets make a series of refactorings to achieve that:
Step 1:
You use your predicate to implement validate function. There are no other calls, nor passing to another functions (higher-order functions accepting a predicate are a typical use for them). Let's change the predicate to a method:
public class Validator {
public DataDao makeDataDao(){
return new DataDao();
}
public boolean validate(String rowId){
return doesRowExist(rowId);
}
private boolean doesRowExist(String rowId) {
return makeDataDao().isRowReturned(rowId);
}
}
Step 2:
Daos are typically singletons (one instance of them is enough). Depending on the frameworks you use, creating a Dao may be more costly than calling a method on it. Let's apply dependency injection principles (class receives it dependencies, not creates them):
public class Validator {
private final DataDao dataDao;
Validator(DataDao dataDao) {
this.dataDao = dataDao;
}
public boolean validate(String rowId){
return doesRowExist(rowId);
}
private boolean doesRowExist(String rowId) {
return dataDao.isRowReturned(rowId);
}
}
If you really need to create Dao each time, you can provide a fecory in the constructor.
Result:
Your class:
has nicer api
is likely more efficient
is trivially testable:
#ExtendWith(MockitoExtension.class)
public class ValidatorTest {
#Mock
DataDao mockDataDao;
#InjectMocks
Validator validator;
#Test
void whenValidateReturnsValueFromIsRowReturned(){
var rowId = "1-abc-34";
doReturn(false)
.when(mockDataDao)
.isRowReturned(rowId);
assertEquals(false, validator.validate(rowId));
}
}
I see your problem as example of more common task: how to stub a field. In your case, you need to stub field doesRowExists.
The common task has common solution: use getter instead: public Predicate<String> getDoesRowExists() { return doesRowExists;} or, with common code style, public Predicate<String> isRowExists() { return doesRowExists;}
So, in your production code you call getter instead field: return isRowExists().test(rowId)
In your test code you just mock this getter: when(isRowExists).thenReturn(true)
Related
I have foolowing class which I would like to mock:
BusineesLayer:
/**
* Created by Alexandr on 14.05.2016.
*/
public class BusineesLayer {
public OrderModel orderModel;
public DbService dbService;
...
public BusineesLayer(OrderModel orderModel,DbService dbService) {
this.orderModel = orderModel;
dbService = dbService;
}
public BusineesLayer() {
}
public boolean checkItemsInDb(List<Items> items) throws HandleOrderExeption {
...
return result
}
public boolean handleOrder() throws HandleOrderExeption {
checkItemsInDb(orderModel.getItemsList());
boolean res =dbService.addOrder(orderModel.getItemsList(),
orderModel.getCustumerName(),
countTotalSum(orderModel.getItemsList())
);
return res;
}
}
I would like to test hanldeOrder() method and in order to make it less excess insted of checkItemsinDb() inside invoke "true";
So, my test looks like this:
#Test
public void handleorderTest() {
...
BusineesLayer layer = Mockito.mock(BusineesLayer.class);
layer.dbService = busineesLayer.dbService;
layer.orderModel = busineesLayer.orderModel;
Mockito.when(layer.checkItemsInDb()).thenReturn(true);
boolean res = layer.handleOrder();
assertThat(res, equalTo(true));
}
but it always return false and doesn't go through handlOrder() at all
Is any ways to solve it? Or how can I refactor my code to test it?
You do not test mocks, you use mocks to help you test.
I think you've just become confused at how you are using mocks. Mocks allow us to simulate and can responses to objects we are testing. If you're testing the handleOrder method, then you should mock anything that interacts with that method, in this case DbService and OrderModel.
#Test
public void handleorderTest() {
BusineesLayer layer = new BusineesLayer(); //we are testing this!
DbService dbService = Mockito.mock(DbService.class);
OrderModel orderModel = Mockito.mock(OrderModel.class);
layer.dbService = dbService;
layer.orderModel = orderModel;
Mockito.when(orderModel.getItemsList()).thenReturn(new ArrayList<Items>());
Mockito.when(dbService.foo()).thenReturn(true);
//mock up multiple calls so your service will provide true
boolean res = layer.handleOrder();
assertThat(res, equalTo(true));
//repeat for false, and so on
}
If, however, you are trying to test the dbService call, then you should create a test for it without the business layer at all. The business layer doesn't depend on anything except calls to other methods, so whether you use those real objects or mocked versions of those objects, the functionality should be the same. The business logic only appears to fail if DBService or OrderModel break, so you would test service and model separately (without involving the business layer) to test those.
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 was playing with org.springframework.data.jpa.domain.Specifications, it's just a basic search :
public Optional<List<Article>> rechercheArticle(String code, String libelle) {
List<Article> result = null;
if(StringUtils.isNotEmpty(code) && StringUtils.isNotEmpty(libelle)){
result = articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)).and(ArticleSpecifications.egaliteLibelle(libelle)));
}else{
if(StringUtils.isNotEmpty(code)){
result= articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)));
}else{
result = articleRepository.findAll(Specifications.where(ArticleSpecifications.egaliteLibelle(libelle)));
}
}
if(result.isEmpty()){
return Optional.empty();
}else{
return Optional.of(result);
}
}
And that's actually working fine but I'd like to write unit tests for this method and I can't figure out how to check specifications passed to my articleRepository.findAll()
At the moment my unit test looks like :
#Test
public void rechercheArticle_okTousCriteres() throws FacturationServiceException {
String code = "code";
String libelle = "libelle";
List<Article> articles = new ArrayList<>();
Article a1 = new Article();
articles.add(a1);
Mockito.when(articleRepository.findAll(Mockito.any(Specifications.class))).thenReturn(articles);
Optional<List<Article>> result = articleManager.rechercheArticle(code, libelle);
Assert.assertTrue(result.isPresent());
//ArgumentCaptor<Specifications> argument = ArgumentCaptor.forClass(Specifications.class);
Mockito.verify(articleRepository).findAll(Specifications.where(ArticleSpecifications.egaliteCode(code)).and(ArticleSpecifications.egaliteLibelle(libelle)));
//argument.getValue().toPredicate(root, query, builder);
}
Any idea?
I was having almost the same problems as you had, and I changed my class that contains Specifications to be an object instead of just one class with static methods. This way I can easily mock it, use dependency injection to pass it, and test which methods were called (without using PowerMockito to mock static methods).
If you wanna do like I did, I recommend you to test the correctness of specifications with integration tests, and for the rest, just if the right method was called.
For example:
public class CdrSpecs {
public Specification<Cdr> calledBetween(LocalDateTime start, LocalDateTime end) {
return (root, query, cb) -> cb.between(root.get(Cdr_.callDate), start, end);
}
}
Then you have an integration test for this method, which will test whether the method is right or not:
#RunWith(SpringRunner.class)
#DataJpaTest
#Sql("/cdr-test-data.sql")
public class CdrIntegrationTest {
#Autowired
private CdrRepository cdrRepository;
private CdrSpecs specs = new CdrSpecs();
#Test
public void findByPeriod() throws Exception {
LocalDateTime today = LocalDateTime.now();
LocalDateTime firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
LocalDateTime lastDayOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());
List<Cdr> cdrList = cdrRepository.findAll(specs.calledBetween(firstDayOfMonth, lastDayOfMonth));
assertThat(cdrList).isNotEmpty().hasSize(2);
}
And now when you wanna unit test other components, you can test like this, for example:
#RunWith(JUnit4.class)
public class CdrSearchServiceTest {
#Mock
private CdrSpecs specs;
#Mock
private CdrRepository repo;
private CdrSearchService searchService;
#Before
public void setUp() throws Exception {
initMocks(this);
searchService = new CdrSearchService(repo, specs);
}
#Test
public void testSearch() throws Exception {
// some code here that interact with searchService
verify(specs).calledBetween(any(LocalDateTime.class), any(LocalDateTime.class));
// and you can verify any other method of specs that should have been called
}
And of course, inside the Service you can still use the where and and static methods of Specifications class.
I hope this can help you.
If you are writing Unit Tests then you should probably mock the call to findAll() method of articleRepository Class using a mocking framework like Mockito or PowerMock.
There is a method verify() using which you can check if the mock is invoked for the particular parameters.
For Example, if you are mocking the findAll() method of articleRepository Class and want to know if this method is called with particular arguments then you can do something like:
Mokito.verify(mymock, Mockito.times(1)).findAll(/* Provide Arguments */);
This will fail the test if mock has not been called for the arguments that you provided.
Your problem is that you are doing too many things within that one method. You should have three different methods that work on articleRepository.
Then you can use mocking as the others suggest:
setup your mocks so that you know which call on articleRepository should be made
verify that exactly the expected calls are happening
Please note: these three methods should be internal; the main point there is: you can't test this method with ONE call from the outside; as it is doing more than one thing, depending on the input that you provide. Thus you need to create at least one test method for each of the potential paths in your code. And that becomes easier (from a conceptual point of view) when you separate your code into different methods.
I have a library I am trying to mock for testing... There is a Java 8 interface with a static method implementation like this:
public interface Router {
public static Router router(Object param) {
return new RouterImpl(param);
}
}
And I am trying to mock that returned value:
PowerMockito.mockStatic(Router.class);
PowerMockito.doReturn(mockRouter).when(Router.router(any()));
But when I run the tests through a debugger, the mock instance is not returned.
I've tried a number of different permutations of the static mocking, but I cannot get the static method to return my mock value. Any thoughts?
You are doing it right, but we will have to wait when mocking static interface method is implemented/fixed in PowerMock. Watch this pull request:
https://github.com/jayway/powermock/issues/510
Note: Good news is that issue in Javassist is already fixed:
https://github.com/jboss-javassist/javassist/pull/11
Why not wrap it in an abstraction that you can mock?
class RouterFactory {
Router createRouter(Object param) {
return Router.router(param);
}
}
And use it in your class
class YourClass {
private final RouterFactory routerFactory;
YourClass(RouterFactory routerFactory) {
this.routerFactory = routerFactory;
}
void doSth() {
// do sth
}
}
Then you can mock the RouterFactory without any problems and you don't have to use Powermock.
Could someone help me with mocking a method call within a method
my code is like :
public class Service {
public List<Bean> Filter(Bean bean){
List<Bean> Filtered_List = getUtilityService.getBeanList();
//Do something
return beanList;
}
}
Now i want to write test case for Service class . How can i mock :
List Filtered_List = getUtilityService.getBeanList(); and set values in it.
The clean solution is to extract UtilityService to a field and pass a mock to the constructor.
public class Service {
private UtilityService utilityService;
public Service(UtilityService utilityService) {
this.utilityService = utilityService;
}
public List<Bean> Filter(Bean bean){
List<Bean> filteredList = utilityService.getBeanList();
//Do something
return beanList;
}
}
You can also introduce a UtilityServiceFactory and have a utilityServiceFactory field in the Service.
public class Service {
private UtilityServiceFactory utilityServiceFactory;
public Service(UtilityServiceFactory utilityService) {
this.utilityServiceFactory = utilityServiceFactory;
}
public List<Bean> Filter(Bean bean){
List<Bean> filteredList = utilityService.create().getBeanList();
//Do something
return beanList;
}
}
If getUtilityService is located in Service class, there is also a dirty solution: partial mock. But I do not recommend it. It's better to refactor your code and use one of previous approaches.
EDIT:
Constructor injection with #InjectMocks is not the best idea but here you are:
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
//other imports
#RunWith(MockitoJUnitRunner.class)
public class ServiceTest {
#Mock
UtilityService utilityService;
#InjectMocks
Service service = new Service(null);
#Test
public void shouldFilterBeans() throws Exception {
//given
given(utilityService.getBeanList()).willReturn(asList(new Bean()));
//when
List<Bean> result = service.filter(new Bean());
//then
assertThat(result).hasSize(1); //probably you want to check something else
}
}
to test a method including its own parameter and return value, like the Filter method in your code, it's enough to just pass a Bean instance to it, and then assert the returned List<Bean> object equals to your expected result. generally, for this kind of method, i think it's no need to use mock frameworks.
but if you really want to test the getUtilityService().getBeanList() method call, you should refactor your code:
addfield UnitilityService service and its corresponding setter method in your class Service
in your unit test code, inject a mocked service using the setter method to the object under test and given a returning value for its getBeanList() method, then invoke your Filter method, finally, verify the method call. for the detailed implementation, you can refer the answer of #woru.