Please find the below code for the DAO & Entity Object and Accessor
@Table(name = "Employee")
public class Employee {
@PartitionKey
@Column(name = "empname")
private String empname;
@ClusteringColumn(0)
@Column(name = "country")
private String country;
@Column(name = "status")
private String status;
}
Accessor:
@Accessor
public interface EmployeeAccessor {
@Query(value = "SELECT DISTINCT empname FROM EMPLOYEE ")
ResultSet getAllEmployeeName();
}
}
DAO getAllEmployeeNames returns a List which are employee names and it will be sorted in ascending order. DAO
public class EmployeeDAOImpl implements EmployeeDAO {
private EmployeeAccessor employeeAccessor;
@PostConstruct
public void init() {
employeeAccessor = datastaxCassandraTemplate.getAccessor(EmployeeAccessor.class);
}
@Override
public List<String> getAllEmployeeNames() {
List<Row> names = employeeAccessor.getAllEmployeeName().all();
List<String> empnames = names.stream()
.map(name -> name.getString("empname")).collect(Collectors.toList());
empnames.sort(naturalOrder()); //sorted
return empnames;
}
}
JUnit Test(mockito):
I am not able to mock the List[datastax row]. How to mock and returns a list of rows with values "foo" and "bar".Please help me in unit test this.
@Category(UnitTest.class)
@RunWith(MockitoJUnitRunner.class)
public class EmployeeDAOImplUnitTest {
@Mock
private ResultSet resultSet;
@Mock
private EmployeeAccessor empAccessor;
//here is the problem....how to mock the List<Row> Object --> com.datastax.driver.core.Row (interface)
//this code will result in compilation error as we are mapping a List<Row> to the ArrayList<String>
//how to mock the List<Row> with a list of String row object
private List<Row> unSortedTemplateNames = new ArrayList() {
{
add("foo");
add("bar");
}
};
//this is a test case to check if the results are sorted or not
//mock the accessor and send rows as "foo" & "bar"
//after calling the dao , the first element must be "bar" and not "foo"
@Test
public void shouldReturnSorted_getAllTemplateNames() {
when(empAccessor.getAllEmployeeName()).thenReturn(resultSet);
when(resultSet.all()).thenReturn(unSortedTemplateNames); //how to mock the List<Row> object ???
//i am testing if the results are sorted, first element should not be foo
assertThat(countryTemplates.get(0), is("bar"));
}
}
Wow! This is overly complex, hard to follow, and not an ideal way to write unit tests.
Using PowerMock(ito) along with "static" references in your own code is not recommended and is a sure sign of a code smells.
First, I am not sure why you decided to use a static reference (e.g. EmployeeAccessor.getAllEmployeeName().all();
inside the EmployeeDAOImpl
class, getAllEmployeeNames()
method) instead of using the instance variable (i.e. empAccessor
), which is more conducive to actual "unit testing"?
The EmployeeAccessor
, getAllEmployeeName()
"interface" method is not static (clearly). However, seemingly, whatever this (datastaxCassandraTemplate.getAccessor(EmployeeAccessor.class);
) generates makes it so (really?), which then requires the use of PowerMock(ito), o.O
Frameworks like PowerMock, and extensions of (i.e. "PowerMockito"), were meant to test and mock code used by your application (unfortunately, but necessarily so) where this "other" code makes use of statics, Singletons, private methods and so on. This anti-pattern really ought not be followed in your own application design.
Second, it is not really apparent what the "Subject Under Test" (SUT) is in your test case. You implemented a test class (i.e. EmployeeDAOImplTest
) for, supposedly, your EmployeeDAOImpl
class (the actual "SUT"), but inside your test case (i.e. shouldReturnSorted_getAllTemplateNames()
), you are calling... countryLocalizationDAOImpl.getAllTemplateNames();
thus testing the CountryLocalizationDAOImpl
class (??), which is not the "SUT" of the EmployeeDAOImplTest
class.
Additionally, it is not apparent that the EmployeeDAOImpl
even uses a CountryLocalizationDAO
instance (assuming an interface here as well), and if it does, then it is certainly something that should be "mocked" when the EmployeeDAOImpl
"interacts" with instances of CountryLocalizationDAO
, particularly in the context of a unit test. The only correlation between the EmployeeDAO
and CountryLocalizationDAO
is that the Employee
has a country
field.
There are a few other problems with your design/setup as well, but anyway.
Here are a few suggestions...
First, let's test what your EmployeeDAOImplTest
is meant to test... EmployeeDAO.getAllEmployeeNames()
in a sorted fashion. This in turn may give you ideas of how to test your "CountryLocalizationDAO
, getAllTemplateNames()
method perhaps (if it even makes sense, i.e. getAllTemplateNames()
is in fact dependent on an Employee's
country
, when Employees
are ordered by name (i.e. "empname
" and accessed via EmployeeAccessor
).
public class EmployeeDAOImpl implements EmployeeDAO {
private final EmployeeAccessor employeeAccessor;
// where does the DataStaxCassandraTemplate reference come from?!
private DataStaxCassadraTemplate datastaxCassandraTemplate = ...;
public EmployeeDAOImpl() {
this(datastaxCassandraTemplate.getAccessor(EmployeeAccessor.class));
}
public EmployeeDAOImpl(EmployeeAccessor employeeAccessor) {
this.employeeAccessor = employeeAccessor;
}
protected EmployeeAccessor getEmployeeAccessor() {
return this.empAccessor;
}
public List<String> getAllEployeeNames() {
List<Row> nameRows = getEmployeeAccessor().getAllEmployeeName().all();
...
}
}
Then in your test class...
public class EmployeeDAOImplUnitTest {
@Mock
private EmployeeAccessor mockEmployeeAccessor;
// SUT
private EmployeeDAO employeeDao;
@Before
public void setup() {
employeeDao = new EmployeeDAOImpl(mockEmployeeAccessor);
}
protected ResultSet mockResultSet(Row... rows) {
ResultSet mockResultSet = mock(ResultSet.class);
when(mockResultSet.all()).thenReturn(Arrays.asList(rows));
return mockResultSet;
}
protected Row mockRow(String employeeName) {
Row mockRow = mock(Row.class, employeeName);
when(mockRow.getString(eq("empname")).thenReturn(employeeName);
return mockRow;
}
@Test
public void getAllEmployeeNamesReturnsSortListOfNames() {
when(mockEmployeeAccessor.getAllEmployeeName())
.thenReturn(mockResultSet(mockRow("jonDoe"), mockRow("janeDoe")));
assertThat(employeeDao.getAllEmployeeNames())
.contains("janeDoe", "jonDoe");
verify(mockEmployeeAccessor, times(1)).getAllEmployeeName();
}
}
Now, you can apply similar techniques if in fact there is an actual correlation between Employees
and CountryLocalizationDAO
via the EmployeeAccessor
.
Hope this helps get you on a better track!
-j