如何模拟 Data Stax Row 对象 [com.datastax.driver.core.Row;] - 单元测试
How to mock the Data Stax Row object[com.datastax.driver.core.Row;] - Unit Test
请找到以下 DAO 和实体对象和访问器的代码
@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
public interface EmployeeAccessor {
@Query(value = "SELECT DISTINCT empname FROM EMPLOYEE ")
ResultSet getAllEmployeeName();
}
}
DAO getAllEmployeeNames returns 员工姓名列表
它将按升序排序。
道
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 测试(mockito):
我无法模拟列表[datastax 行]。如何模拟和 returns 具有值 "foo" 和 "bar" 的行列表。请帮助我对此进行单元测试。
@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"));
}
}
哇!这过于复杂,难以遵循,并且不是编写单元测试的理想方式。
不推荐在您自己的代码中使用 PowerMock(ito) 和 "static" 引用,这肯定是代码有异味的标志。
首先,我不确定您为什么决定使用静态引用(例如 EmployeeAccessor.getAllEmployeeName().all();
在 EmployeeDAOImpl
class、getAllEmployeeNames()
方法中)而不是使用实例变量(即empAccessor
),更有利于实际"unit testing"?
EmployeeAccessor
, getAllEmployeeName()
"interface" 方法不是静态的(显然)。然而,表面上看,无论这个 (datastaxCassandraTemplate.getAccessor(EmployeeAccessor.class);
) 生成什么都会使它如此(真的吗?),然后需要使用 PowerMock(ito)、o.O
PowerMock 等框架及其扩展(即“PowerMockito”)旨在测试和模拟您的应用程序使用的代码(不幸的是,但必然如此)此 "other" 代码使用了静态、单例、私有方法等。在您自己的应用程序设计中确实不应该遵循这种反模式。
其次,“被测对象”(SUT)在您的测试用例中的含义并不明显。您实施了一个测试 class(即 EmployeeDAOImplTest
),据推测,您的 EmployeeDAOImpl
class(实际的 "SUT"),但在您的测试用例中(即 shouldReturnSorted_getAllTemplateNames()
), 你正在调用... countryLocalizationDAOImpl.getAllTemplateNames();
从而测试 CountryLocalizationDAOImpl
class (??), 这不是 [=19= 的 "SUT" ] class.
此外,EmployeeDAOImpl
甚至使用了一个 CountryLocalizationDAO
实例(假设这里也有一个接口)并不明显,如果确实如此,那么它肯定应该是 "mocked" 当 EmployeeDAOImpl
"interacts" 带有 CountryLocalizationDAO
的实例时,特别是在单元测试的上下文中。 EmployeeDAO
和 CountryLocalizationDAO
之间的唯一关联是 Employee
有一个 country
字段。
你的 design/setup 还有一些其他问题,但无论如何。
这里有一些建议...
首先,让我们以有序的方式测试一下您的 EmployeeDAOImplTest
是要测试什么... EmployeeDAO.getAllEmployeeNames()
。这反过来可能会让您了解如何测试您的“CountryLocalizationDAO
,getAllTemplateNames()
方法(如果它甚至有意义,即 getAllTemplateNames()
实际上依赖于 Employee's
country
,当 Employees
按名称排序时(即“empname
”并通过 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();
...
}
}
那么在你的测试中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();
}
}
现在,如果 Employees
和 CountryLocalizationDAO
通过 EmployeeAccessor
.
之间存在实际相关性,您可以应用类似的技术
希望这可以帮助您走上更好的轨道!
-j
请找到以下 DAO 和实体对象和访问器的代码
@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
public interface EmployeeAccessor {
@Query(value = "SELECT DISTINCT empname FROM EMPLOYEE ")
ResultSet getAllEmployeeName();
}
}
DAO getAllEmployeeNames returns 员工姓名列表 它将按升序排序。 道
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 测试(mockito):
我无法模拟列表[datastax 行]。如何模拟和 returns 具有值 "foo" 和 "bar" 的行列表。请帮助我对此进行单元测试。
@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"));
}
}
哇!这过于复杂,难以遵循,并且不是编写单元测试的理想方式。
不推荐在您自己的代码中使用 PowerMock(ito) 和 "static" 引用,这肯定是代码有异味的标志。
首先,我不确定您为什么决定使用静态引用(例如 EmployeeAccessor.getAllEmployeeName().all();
在 EmployeeDAOImpl
class、getAllEmployeeNames()
方法中)而不是使用实例变量(即empAccessor
),更有利于实际"unit testing"?
EmployeeAccessor
, getAllEmployeeName()
"interface" 方法不是静态的(显然)。然而,表面上看,无论这个 (datastaxCassandraTemplate.getAccessor(EmployeeAccessor.class);
) 生成什么都会使它如此(真的吗?),然后需要使用 PowerMock(ito)、o.O
PowerMock 等框架及其扩展(即“PowerMockito”)旨在测试和模拟您的应用程序使用的代码(不幸的是,但必然如此)此 "other" 代码使用了静态、单例、私有方法等。在您自己的应用程序设计中确实不应该遵循这种反模式。
其次,“被测对象”(SUT)在您的测试用例中的含义并不明显。您实施了一个测试 class(即 EmployeeDAOImplTest
),据推测,您的 EmployeeDAOImpl
class(实际的 "SUT"),但在您的测试用例中(即 shouldReturnSorted_getAllTemplateNames()
), 你正在调用... countryLocalizationDAOImpl.getAllTemplateNames();
从而测试 CountryLocalizationDAOImpl
class (??), 这不是 [=19= 的 "SUT" ] class.
此外,EmployeeDAOImpl
甚至使用了一个 CountryLocalizationDAO
实例(假设这里也有一个接口)并不明显,如果确实如此,那么它肯定应该是 "mocked" 当 EmployeeDAOImpl
"interacts" 带有 CountryLocalizationDAO
的实例时,特别是在单元测试的上下文中。 EmployeeDAO
和 CountryLocalizationDAO
之间的唯一关联是 Employee
有一个 country
字段。
你的 design/setup 还有一些其他问题,但无论如何。
这里有一些建议...
首先,让我们以有序的方式测试一下您的 EmployeeDAOImplTest
是要测试什么... EmployeeDAO.getAllEmployeeNames()
。这反过来可能会让您了解如何测试您的“CountryLocalizationDAO
,getAllTemplateNames()
方法(如果它甚至有意义,即 getAllTemplateNames()
实际上依赖于 Employee's
country
,当 Employees
按名称排序时(即“empname
”并通过 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();
...
}
}
那么在你的测试中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();
}
}
现在,如果 Employees
和 CountryLocalizationDAO
通过 EmployeeAccessor
.
希望这可以帮助您走上更好的轨道!
-j