我们如何为下面的代码编写模仿?它是用普通的JDBC编写的。我需要创建一个包含main方法的所有代码的模拟程序(这将驱动更新数据的所有逻辑)。
在模拟过程中确实需要帮助,避免插入实际数据。有人可以引导我吗?
public class PaytPaytmBilling {
private static Category logger = Category.getInstance(PaytPaytmBilling.class);
private static InputStream inputS = XY.class.getResourceAsStream("/paytm.properties");
private static final INSERT_QUERY = "INSERT STATEMENT";
private static void insertPaytPaytmBilling(ArrayList allPaytPaytmBill) throws Exception{
conn = getConnection(userId, passwd, prop.getProperty("databaseURL"));
String childSql = buildInsertPaytPaytmBillSql();
PreparedStatement pStatement = conn.prepareStatement(childSql);
for (int i=0; i<allPaytPaytmBill.size(); i++){
PaytPaytmBill PaytmBill = (PaytPaytmBill) allPaytPaytmBill.get(i);
pStatement.setString(1, PaytmBill.getXX());
pStatement.setString(2, PaytmBill.getYY());
pStatement.setString(3, PaytmBill.getAA());
pStatement.setLong(4, PaytmBill.getBB());
pStatement.setLong(5, PaytmBill.getCC));
pStatement.setString(6, PaytmBill.getDD());
pStatement.setInt(7, PaytmBill.getEE());
pStatement.setInt(8, PaytmBill.getFF());
pStatement.setString(9, "");
pStatement.setString(10, "");
pStatement.execute();
}
pStatement.close();
conn.close();
}
private static void getDbConn() throws Exception {
// Here get DB connection
}
public static void main(String[] args) throws Exception
{
ArrayList allPaytPaytmBill = new ArrayList();
XY.init();
getDbConn();
// This query reads data from other tables and creates the data..
String qmrString = qmr.buildQmrSql();
allPaytPaytmBill = qmr.getAllMemberData(qmrString);
insertPaytPaytmBilling(allPaytPaytmBill);
}
}
Mockito测试类:
@RunWith(MockitoJUnitRunner.class)
public class PaytmBillingTest {
private static Category logger = Category.getInstance(PaytmBillingTest.class);
@Mock
private DataSource ds;
@Mock
private Connection c;
@Mock
private PreparedStatement stmt;
@Mock
private ResultSet rs;
private ArrayList<PaytmBill> allPaytmBill;
@Before
public void before() {
allPaytmBill = new ArrayList<>();
PaytmBill PaytmBill = new PaytmBill();
PaytmBill.setAA("1182");
PaytmBill.setBB("5122");
PaytmBill.setCC("201807");
PaytmBill.setDD(0L);
PaytmBill.setEE(100);
PaytmBill.setFF(0);
PaytmBill.setGG(0);
PaytmBill.setHH("A");
PaytmBill.setII(null);
PaytmBill.setJJ(null);
allPaytmBill.add(PaytmBill);
}
@Test
public void testPaytmBilling() {
PaytmBilling PaytmBilling = new PaytmBilling();
}
}
答案 0 :(得分:1)
首先,您似乎没有在使用真实代码。例如,您添加了conn = getConnection(...)
,但是代码调用了conn
,变量public class PaytPaytmBilling {
private static final String CHILD_SQL = "SELECT bladiebla...";
private DataSource dataSource;
public PaytPaytmBilling(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertPaytPaytmBilling(List<PaytmBill> allPaytPaytmBill) {
// keeping the example simple here.
// don't use String literals for the parameters below but read
// them from Properties (which you can mock for the unit test)
Connection conn = dataSource.getConnection("userId", "passwd", "url");
PreparedStatement pStatement = conn.prepareStatement(CHILD_SQL);
for (int i=0; i<allPaytPaytmBill.size(); i++){
PaytPaytmBill PaytmBill = (PaytPaytmBill) allPaytPaytmBill.get(i);
pStatement.setString(1, PaytmBill.getXX());
pStatement.setString(2, PaytmBill.getYY());
pStatement.setString(3, PaytmBill.getAA());
// ...
pStatement.execute();
}
pStatement.close();
conn.close();
}
没有在任何地方声明,等等。这使得真正解决问题变得更加困难。
查看单元测试,您想模拟PaytPaytmBilling使用的某些类的实例,例如DataSource,Connection和PreparedStatement。这些被称为“依赖项”。
为此,您需要更改PaytPaytmBilling以便“注入”这些依赖项(请参见Dependency Injection)。这意味着它们是通过构造函数或设置器(或某些框架通过在字段上添加注释)提供给PaytPaytmBilling的。
在当前代码中,依赖关系是通过PaytPaytmBilling自身获得的(例如,通过调用静态方法或创建新实例),并且无法对其进行模拟(除非通过某些我不建议您使用的黑魔法模拟框架)立即进入。)
要编写好的单元测试,您需要编写(或重构)可测试的代码,这意味着将注入依赖项,而不是在类内部获取。还应避免使用静态方法和数据(可以使用常量),因为它们与依赖项注入和可测试的代码配合使用效果不佳。
例如,可以通过如下构造函数注入数据源:
@RunWith(MockitoJUnitRunner.class)
public class PaytmBillingTest {
// this will cause Mockito to automatically create an instance
// and inject any mocks needed
@InjectMocks
private PaytmBilling instanceUnderTest;
@Mock
private DataSource dataSource;
// connection is not directly injected. It is obtained by calling
// the injected dataSource
@Mock
private Connection connection;
// preparedStatement is not directly injected. It is obtained by
// calling the connection, which was obtained by calling the
// injected dataSource
@Mock
private PreparedStatement preparedStatement;
private List<PaytmBill> allPaytmBill;
@Before
public void before() {
allPaytmBill = new ArrayList<>();
PaytmBill paytmBill = new PaytmBill();
paytmBill.setAA("1182");
paytmBill.setBB("5122");
paytmBill.setCC("201807");
paytmBill.setDD(0L);
paytmBill.setEE(100);
paytmBill.setFF(0);
paytmBill.setGG(0);
paytmBill.setHH("A");
paytmBill.setII(null);
paytmBill.setJJ(null);
allPaytmBill.add(PaytmBill);
}
@Test
public void testPaytmBilling() {
// given
when(dataSource.getConnection(anyString(), anyString(), anyString())).thenReturn(connection);
when(connection.prepareStatement(anyString())).thenReturn(preparedStatement);
// when
instanceUnderTest.insertPaytPaytmBilling(allPaytPaytmBill);
// then
verify(pStatement).setString(1, paytmBill.getXX());
verify(pStatement).setString(2, paytmBill.getYY());
verify(pStatement).setString(3, paytmBill.getAA());
// ...
verify(pStatement).execute();
verify(pStatement).close();
verify(connection).close();
}
如果您像上面那样重新编写代码,则可以这样进行测试:
Connection conn = dataSource.getConnection("userId", "passwd", "url");
PreparedStatement pStatement = conn.prepareStatement(childSql);
try {
// processing steps
}
finally {
pStatement.close();
conn.close();
}
与您的代码无关的建议:最好在finally块中关闭资源,或使用try-with resources。在您体内,如果对资源进行处理时发生异常,则当前代码资源将不会关闭:
try (Connection conn = dataSource.getConnection("userId", "passwd", "url"),
PreparedStatement pStatement = conn.prepareStatement(childSql)) {
// processing steps
}
或尝试使用资源:
{{1}}
由于Connection和PreparedStatement实现了AutoCloseable接口,因此在try块结束时它们将自动关闭。从Java 7开始是可能的。