here are examples of a methods :
public <T> T save(final T o){
return (T) sessionFactory.getCurrentSession().save(o);
}
public <T> T get(final Class<T> type, final Long id){
return (T) sessionFactory.getCurrentSession().get(type, id);
}
public <T> List<T> getFieldLike(final Class<T> type, final String propertyName,
final String value, final MatchMode matchMode) {
final Session session = sessionFactory.getCurrentSession();
final Criteria crit = session.createCriteria(type);
crit.add(Restrictions.like(propertyName, value, matchMode));
return crit.list();
}
Any tips on either unit or integration test these ? Pass in a mock session ?
About the only thing you could do in a unit test is mock Session and Criteria and set expectations - I've done this for a few cases using JMock and ended up having to write a Hamcrest matcher for the Restricitons. I'm not convinced there's much value in it, other than blindly increasing the test coverage.
On the other hand - writing an integration test here would be of definite use, set up an in memory database with some data and assert that the methods return the correct objects
An example for integration test for get():
// if you can inject the object:
// #Inject
// public MyTestDAO<MyType> dao;
//
#Test
public testGet() throws Exception {
Session session = HibernateUtils.getSessionFactory().getCurrentSession();
MyTestDAO<MyType> dao = new MyTestDAO<MyType>();
// if you use DI facility, check against null
// assertNotNull(dao)
MyType myType = dao.get(Test.class, 1L);
assertNotNull(myType);
assertEqual(myType, equalObj);
// more asserts?
}
if you use spring framework, you can use spring-test module to use DI using spring context and class runner:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:spring.xml"})
By your question I assume you are managing your sessions yourself. I will talk about the unit testing part. Integration tests can be done on an in memory database during integration. H2 or Derby are one of the most used ones as far as I know.
You can go by passing a mock session to your DAO, but what will happen if one of your colleagues writes a unit test and forgets to pass a mock session? Do you hit database? If you DO NOT want to hit database, this approach can be a problem
What a better approach would be to use an abstract factory pattern to even ACQUIRE the dao. Basically your code is currently like this:
MyDao.get(someId);
However, you can go in the following way:
If you define your Dao first like this:
public interface IDao <SomeGenerics> {
public <T> T get(Class<T> type, ID key);
//more generic methods
}
Then you can have an implementation of the Dao, which is like this:
public class MyDao <SomeGenerics> implements IDao<SomeGenerics> {
public <T> T get(Class<T> type, ID key){
//some real session stuff
}
//...more real session stuff
}
Then in your unit tests you can define a mock of your IDao interface, kinda like this:
public class MyDaoMock <SomeGenerics> implements IDao<SomeGenerics> {
//this thingy can hold a small array of mock instances
private ArrayList<T> mockInstances;
public <T> T get(Class<T> type, ID key){
//some fake stuff, kinda like this;
for (T mockInstance : mockInstances) {
if ( mockInstance.getId().equals(key) ) {//here i assume your T has a method getId, you figure out the kinks
return mockInstance;
}
}
//if not found, emulate your persistence's behavior, return null, throw an exception or do whatever
return null;
}
//...more fake stuff
}
Now you have an interface and two implementations, one for your production code and one for your unit tests. Now all you have to do is to implement the factory pattern to give you the right dao in production and in testing code.
Related
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)
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 created a common method in which I will pass a DAO but it will not be a one DAO. Like i will be passing not only StudentDao but also TeachersDao and ClubsDao.
Originally, this is my method:
public static String getSomething(StudentDao, String id){
Properties proFind = new Properties();
proFind.put(StudentDao.ID, id);
dao.select(proFind).get(0);
return somethingINeed;
}
But then I've decided that to use only one method, make it something generic..
Somthing like this:
public static <T> String getSomething(Class<T> dao, String id){
Properties proFind = new Properties();
proFind.put(StudentDao.ID, id);
dao.select(proFind).get(0);
return somethingINeed;
}
but this is not correct.
So my objective is to pass any Dao in that method.
Did i miss something in java?
Any idea or enlightenment is greatly appreciated.
[EDIT]
All my Daos extends Dao which is and interface.
My concern is just this method in which how I can use any Dao.
The attributes used can be found in the interface Dao also.
I agree with Kayaman's comment above.
Your service/business tier should be interfacing with multiple DAOs to perform CRUD operations on different entities e.g. Student, Teacher.
public class MyService {
private StudentDao studentDao;
private TeacherDao teacherDao;
// Daos injected
public Student findStudent(Long id) {
return this.studentDao.find(id);
}
// Other methods involving students or teachers
}
Trying to have one generic DAO is cumbersome and not good design in my opinion.
If you have a base DAO and base entity classes, you can still push a lot of the boilerplate CRUD code into the base classes. When I first started using DAOs, I found the following article very useful: Don't repeat the DAO!
thats why java created Interfaceenter link description here or Inheritance
just create a DAO interface or base class and change your method to
public static String getSomething(Dao dao, String id)
Use this
public static String getSomething(Object dao, String id){
if(dao instanceOf StudentDao){
// do your code
}
else if(dao instanceOf AnotherDao){
// do your code
}
and so on.............
I think the issue is explained best with an example.
public class MyService {
private OtherService theOther;
public void setTheOther(OtherService srv) { theOther = srv; }
public void myBusinessStuffFor(int id) {
theOther.applyToAllWith(id, new OtherService.Action() {
public void apply(Object whatever) {
doTheHardBusinessStuffWith(whatever);
}
}
}
private void doTheHardBusinessStuffWith(Object whatever) {
// here the business stuff provided by MyService
}
}
public interface OtherService {
void applyToAllWith(int id, Action action);
public interface Action {
void applyOn(Object whatever);
}
}
I like this pattern, because it's very cohesive. Action interfaces are paired with their Services. Business logic is not cluttered in many classes. Subclasses are only providing data to the action and don't have to be busy. I adopted it from here ( http://jamesladdcode.com/?p=12). The problem is that i didn't found a good solution for testing the behavior in the "doTheHardBusinessStuffWith(Object whatever)" method if i mock the otherService. With the mock i have to care how the business method gets called. But how can i do this. I use mockito and tried it with a ArgumentCapture already. But it don't feels right because of abusing ArgumentCapture.
I would like to know if the pattern used in class MyService.myBusinessStuffFor(int id) has a name (is it strategy pattern)?
But my major questions is how to make this code testable with mock of OtherService?
The other service is not really a business service in this case. Its only responsibility is to find the objects from the given ID, and apply the given action on these objects. Functionally, this is equivalent to the following code:
Set<Object> objects = otherService.getObjectsWithId(id);
for (Object o : objects) {
doTheHardBusinessStuffWith(o);
}
Make doTheHardBusinessStuffWith protected. Create a unit test for this method. This is the most important unit test: the one that tests the business logic.
If you really want to unit-test myBusinessStuffFor, what you could do is create a mock OtherService (and I mean implement this mock youself, here), that is built from a Set of objects, and applies its given action to all the objects in the set. Create a partial mock of MyService where the doTheHardBusinessStuffWith method is mocked, and which is injected with you mock OtherService. Call myBusinessStuffFor on the partial mock, and verify that doTheHardBusinessStuffWith has been called with every object of the set of objects.
You talk about mocking the OtherService. I don't know which mocking framework are you using; but you should be able to create a mock that just calls the applyOn method of the Action that gets passed to the applyToAllWith method, passing a mock object as the argument. In mockito, for example, this would be stubbed something like this.
doAnswer( new Answer<Object>(){
public Object answer( InvocationOnMock invocation ){
((Action) invocation.getArguments()[ 1 ]).applyOn( mockObject );
return null;
}}).when( mockOtherService ).applyToAllWith( anyInt(), any( Action.class ));
where mockOtherService is the mock you've created for the OtherService interface, and mockObject is whichever mock you want to pass to doTheBusinessHardStuffWith.