【问题标题】:How to test PROCEDURE in PostgreSQL with pgTAP?如何使用 pgTAP 在 PostgreSQL 中测试 PROCEDURE?
【发布时间】:2018-12-13 20:06:39
【问题描述】:

是否有使用 pgTap 对 PostgreSQL 11+ PROCEDURE(不是 FUNCTION)进行单元测试的最佳实践。

例如,如何建议对这样的存储过程进行单元测试:

CREATE OR REPLACE PROCEDURE foo.do_something(IN i_value INT)
AS
$$
BEGIN
  PERFORM foo.call_function_1(i_value);
  COMMIT;      
  PERFORM foo.call_function_2(i_value);
  COMMIT;      
  CALL foo.another_procedure(i_value);
END;
$$
LANGUAGE plpgsql;

这变得很困难,因为 pgTap 单元测试通过这样的存储函数运行:

SELECT * FROM runtests('foo'::NAME);

这在事务中执行,因此无法执行通过调用COMMITROLLBACK 修改事务状态的存储过程。

【问题讨论】:

  • 我发布了自己的答案,但如果有人有任何想法,我仍然愿意接受其他想法。

标签: postgresql postgresql-11 pgtap


【解决方案1】:

这是我在使用接口和其他语言的模拟框架的启发下提出的一种方法。

首先我们将COMMIT 操作移动到这样的存储过程中:

CREATE PROCEDURE foo.do_commit()
AS
$$
BEGIN
  COMMIT;
END;
$$
LANGUAGE plpgsql;

然后我们将实际存储过程更改为调用do_commit,而不是直接使用COMMIT 命令。例如:

CREATE OR REPLACE PROCEDURE foo.do_something(IN i_value INT)
AS
$$
BEGIN
  PERFORM foo.call_function_1(i_value);
  CALL foo.do_commit();
  CALL foo.another_procedure(i_value);
END;
$$
LANGUAGE plpgsql;

由于单元测试是在回滚的事务中执行的,我们可以将do_commit 调用临时替换为模拟出来的测试。测试可能如下所示:

CREATE FUNCTION test.test_do_something()
RETURNS SETOF TEXT 
AS 
$$
BEGIN
  CREATE TEMPORARY TABLE commit_calls
  (
    commit_call BOOLEAN NOT NULL DEFAULT TRUE
  )
  ON COMMIT DROP;

  CREATE TEMPORARY TABLE function_calls
  (
    the_value INT NOT NULL
  )
  ON COMMIT DROP;

  CREATE OR REPLACE PROCEDURE foo.do_commit()
  AS
  $mock_do_commit$
  BEGIN
    INSERT INTO commit_calls (commit_call)
    VALUES (DEFAULT);
  END;
  $mock_do_commit$
  LANGUAGE plpgsql;

  CREATE OR REPLACE FUNCTION foo.call_function_1(i_value INT)
  RETURNS VOID
  AS
  $mock_call_function_1$
    INSERT INTO function_calls (the_value)
    VALUES (i_value);
  $mock_call_function_1$
  LANGUAGE sql;

  -- EXECUTE
  CALL foo.do_something(9);
  CALL foo.do_something(100);

  -- VERIFY
  RETURN NEXT assert.is((SELECT COUNT(*) FROM commit_calls)::INT, 2, 'verify transaction commits');
  RETURN NEXT assert.bag_eq(
    'SELECT the_value FROM function_calls',
    'VALUES (9), (100)',
    'verify function call values');
END;
$$
LANGUAGE plpgsql;

这个想法是暂时模拟出实际的函数调用以进行测试。
这样就可以在不提交实际事务的情况下对存储过程进行单元测试。
当测试结束时,它会回滚事务并丢弃所有更改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    • 1970-01-01
    相关资源
    最近更新 更多