【问题标题】:Changing Mocked ResultSet value each time a SQL statement is run每次运行 SQL 语句时更改 Mocked ResultSet 值
【发布时间】:2014-06-01 19:57:12
【问题描述】:

我正在使用 Mockrunner 为 select 语句创建一个模拟结果集。我有一个执行 select 语句(返回单个值)的循环。我想让结果集每次都返回一个不同的值,但是我找不到任何关于如何根据调用语句的时间来指定结果集返回值的信息。这是代码的伪代码sn-p:

在测试代码中:

String selectSQL = "someselectStmt";
StatementResultSetHandler stmtHandler = conn.GetStatementResultSetHandler();
MockResultSet result = stmtHandler.createResultSet();
result.addRow(new Integer[]{new Integer(1)});
stmtHandler.prepareResultSet(selectSQL, result);

在实际的目标类中:

Integer[] Results = getResults(selectSQL);

while(Results.length != 0){
    //do some stuff that change what gets returned in the select stmt
    Results = getResults(selectSQL)
}

所以基本上我想在第一次返回 1,第二次返回 2,第三次返回什么。到目前为止,我还没有找到任何可以利用的东西来实现这一目标。模拟的 select 语句将始终返回与它关联的最后一个结果集(例如,如果我创建了两个 MockResultSets 并将它们与相同的 select stmt 关联)。这个想法可行吗?

【问题讨论】:

  • 你可以使用 Mockito 吗?您可以创建一个正在进行的存根,它在后续调用中返回不同的值。
  • 我没试过 Mockito。我会研究一下,看看我们是否可以在代码中利用它。

标签: java sql unit-testing mockrunner


【解决方案1】:

在 Java 和 SQL 中工作的循环控制流

如果您使用 Java 编写此代码,则可以通过循环控制流语句(例如 do-while-loop)来使您的代码执行调用返回不同的有序结果。这个 Wikipedia 参考对使用 Java 和不同编程语言的实现之间的 do-while-loop 对比进行了很好的讨论。

观察带来的一些额外影响:

您使用Mockrunner 工具的工作线索:

模拟的 select 语句将始终返回与它关联的最后一个结果集(例如,如果我创建了两个 MockResultSet 并将它们与同一个 select stmt 关联)

之所以如此,是因为SELECT 语句实际上也必须更改,否则重复查询也会重复结果输出。一个线索是,您的 SQL 在整个代码执行过程中都以文字字符串值的形式存在。字符串可以通过代码和简单的字符串操作来改变。

String selectSQL = "someselectStmt";
StatementResultSetHandler stmtHandler = conn.GetStatementResultSetHandler();
MockResultSet result = stmtHandler.createResultSet();
result.addRow(new Integer[]{new Integer(1)});
stmtHandler.prepareResultSet(selectSQL, result);

除了selectSQL变量外,还要为数值变量添加一行,以跟踪SQL语句执行了多少次:

Int queryLoopCount = 0;

在以下目标类中:

Integer[] Results = getResults(selectSQL);

while(Results.length != 0){
//do some stuff that change what gets returned in the select stmt
Results = getResults(selectSQL)
}

尝试按照此示例重写此 WHILE 循环控制。在您的伪代码中,您将继续从对 getResults(selectSQL); 的调用中提取相同的数据,因为查询在每次通过代码时都保持不变。

设置测试架构和示例 SQL 语句

这里是使用一个包含“testdata”输出的单个 MySQL 表的小检查,该输出将被馈送到某些结果集中。 ID 列可能是一种唯一标识每个不同记录或“测试用例”的方法

SQL Fiddle

MySQL 5.5.32 架构设置

CREATE TABLE testCaseData 
    (
     id int primary key,
     testdata_col1 int,
     testdata_col2 varchar(20),
     details varchar(30)
    );

INSERT INTO testCaseData
(id, testdata_col1, testdata_col2, details)
VALUES
(1, 2021, 'alkaline gab', 'First Test'),
(2, 322, 'rebuked girdle', '2nd Test'),
(3, 123, 'municipal shunning', '3rd Test'),
(4, 4040, 'regal limerick', 'Skip Test'),
(5, 5550, 'admonished hundredth', '5th Test'),
(6, 98, 'docile pushover', '6th Test'),
(7, 21, 'mousiest festivity', 'Last Test');

commit;

查询 1 查看所有测试数据

SELECT id, testdata_col1, testdata_col2, details
  FROM testCaseData

Results

| ID | TESTDATA_COL1 |        TESTDATA_COL2 |    DETAILS |
|----|---------------|----------------------|------------|
|  1 |          2021 |         alkaline gab | First Test |
|  2 |           322 |       rebuked girdle |   2nd Test |
|  3 |           123 |   municipal shunning |   3rd Test |
|  4 |          4040 |       regal limerick |  Skip Test |
|  5 |          5550 | admonished hundredth |   5th Test |
|  6 |            98 |      docile pushover |   6th Test |
|  7 |            21 |   mousiest festivity |  Last Test |

查询2只查询表中的第一条记录

SELECT id, testdata_col1, testdata_col2, details
  FROM testCaseData
 WHERE id = 1

Results

| ID | TESTDATA_COL1 | TESTDATA_COL2 |    DETAILS |
|----|---------------|---------------|------------|
|  1 |          2021 |  alkaline gab | First Test |

查询3查询表中的特定测试记录

SELECT id, testdata_col1, testdata_col2, details
  FROM testCaseData
 WHERE id = 2

Results

| ID | TESTDATA_COL1 |  TESTDATA_COL2 |  DETAILS |
|----|---------------|----------------|----------|
|  2 |           322 | rebuked girdle | 2nd Test |

查询4返回和限制输出集大小

SELECT id, testdata_col1, testdata_col2, details
  FROM testCaseData
 WHERE id < 5

Results

| ID | TESTDATA_COL1 |      TESTDATA_COL2 |    DETAILS |
|----|---------------|--------------------|------------|
|  1 |          2021 |       alkaline gab | First Test |
|  2 |           322 |     rebuked girdle |   2nd Test |
|  3 |           123 | municipal shunning |   3rd Test |
|  4 |          4040 |     regal limerick |  Skip Test |

编写参数化 SQL 语句

我不知道这种语法差异是否会产生与您的伪代码完全相同的结果,但我建议从我知道已经工作的代码结构的引用中使用它。

set condition value before loop
do{
    // do some work
    // update condition value
}while(condition);

WHILE 条件位于语句的末尾,并且应该基于对循环块内的值的更改。我们现在将介绍第二个变量,一个 int,它跟踪循环的迭代次数:

String selectSQL = "someselectStmt";
String[] Results; = getResults(selectSQL);

// set condition value before loop 
queryLoopCount = 0

do{
    // do some work
    Results = getResults(selectSQL);

    // update condition value
    queryLoopCount = queryLoopcount + 1;

}while(queryLoopCount < 6);

selectSQL 来自哪里:

SELECT id, testdata_col1, testdata_col2, details
  FROM testCaseData
 WHERE id = 2;

并使用内置参数适应:

selectSQL = 'SELECT id, testdata_col1, testdata_col2, details
  FROM testCaseData
 WHERE id = ' + queryLoopCount;

混合字符串和整数值可能不是问题,因为this reference on concatenated(+) 值表明:任何连接到字符串的内容都会转换为字符串(例如,“重量 =”+ 千克)。

特殊案例要求的想法

  • 您可以引入自己的编号顺序来获取每个案例的记录以循环浏览参考表。通过引入ORDER BY 语句并更改键ORDER BY 值有很多可能性。

  • “跳过”案例。在 Do-While 循环中,添加 IF-THEN 语句以有条件地跳过特定记录。

    set condition value before loop
    do{
    
        if ( queryLoopCount <> 4 ) {
        // do some work}
    
        // update condition value
        queryLoopCount = queryLoopCount + 1;
    
    }while(condition);
    

    使用 if-then 循环,此代码示例将处理所有测试记录,但会跳过 ID = 4 的记录并继续执行,直到满足 while 循环条件。

【讨论】:

  • 嗨,理查德,感谢您的回复。不幸的是,这个特定代码的设置方式我实际上无法更改 select 语句本身。此 select 语句不知道任何特定的限定符(例如主 ID)。因此,它将返回一组行(比如 10)。然后,我们将此返回集限制为第一个,然后处理该项目。该项目的处理将防止它在重新运行时从同一个 select 语句返回(给我们 9 个结果并获取第一个)。我想知道是否有办法模拟这种类型的 stmt。
  • 请告诉我更多关于您的输出行的信息。甚至可以识别composite unique key 吗?如果没有,确保在使用相同的 SQL 语句时不会再次拾取记录的一种蛮力方法是在处理过的记录后删除它(不是真的推荐,但这是可能的)。您的主要问题是 something 持久性必须存在于您的驱动过程的范围之外。
  • 基本上代码是这样编写的,它连接两个表并返回一组值,但一次只处理一行。该行的处理会将其从连接表中删除,因此当 sql 再次运行时,它不会返回该特定行,因此它将处理集合中的下一行。因此,如果它返回值 1-10,它将处理值 1,并且第二次通过它只会返回值 2-10,然后它将处理值 2 等等。这不是最好的代码,但遗憾的是,这是典型的遗留代码。这能回答你要找的东西吗?我不确定。
猜你喜欢
  • 2022-01-25
  • 1970-01-01
  • 2010-11-13
  • 1970-01-01
  • 1970-01-01
  • 2016-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多