首页 > 解决方案 > 为我的 Postgres 对象编写基本测试代码

问题描述

我想为我的 Postgres 11.5 数据库中的各种对象构建一些测试代码,并且想知道是否有一种直接的方法可以在直接 SQL 中实现简单的检查。例如,我有一个简单的域,可以接受三个值中的任何一个,即不区分大小写。这只是我选择的一个示例,因为测试用例是有限且简单的。

DROP DOMAIN IF EXISTS domains.test_outcome;

CREATE DOMAIN domains.test_outcome AS
    citext
    NOT NULL
    CONSTRAINT test_outcome_legal_values
        CHECK(
            VALUE IN ('pass','warning','fail')
     );

COMMENT ON DOMAIN domains.test_outcome IS
    'The test_outcome must be pass, warning, or fail, case-insensitive.';

下面是一些简单的测试语句,它们可以使用好值和坏值:

-- Good values
select 'warning'::test_outcome;
select 'fail'::test_outcome;
select 'PASS'::test_outcome;
select 'WARNING'::test_outcome;
select 'FAIL'::test_outcome;

-- Bad values
select NULL::test_outcome;  
select ''::test_outcome;  
select 'foo'::test_outcome;

我想做的是为每种情况获取一行,而不是因错误而崩溃。我尝试过使用DO块,并且可以使用 PL/PgSQL 函数。这是DO我尝试过的代码:

DO $TESTS$

BEGIN
-- Good values
    select 'warning'::test_outcome;
    select 'fail'::test_outcome;
    select 'PASS'::test_outcome;
    select 'WARNING'::test_outcome;
    select 'FAIL'::test_outcome;

-- Bad values
    select NULL::test_outcome;  
    select ''::test_outcome;  
    select 'foo'::test_outcome;

EXCEPTION WHEN OTHERS THEN
      RAISE NOTICE 'Error Name:%',  SQLERRM;
      RAISE NOTICE 'Error State:%', SQLSTATE;
END;
$TESTS$

我得到的是几条通知。据我所知,我无法将这些与具体的陈述联系起来,而且我对成功案例一无所获。

NOTICE:  Error Name:query has no destination for result data
NOTICE:  Error State:42601
DO
Command completed successfully. (Line 20)

我已经看到周围有一些 PG 单元测试框架,使用我们不使用的语言。有没有办法在直接 SQL 或 PL/PgSQL 中进行类似上面的简单测试?

标签: postgresqltesting

解决方案


没有什么我知道的,但也许以下可以为您提供一个模板。
我需要修改您的域定义,稍微删除其中的 NOT NULL 约束。下面的脚本声明了test_outcome的工作变量。但是 Postgres 强制执行 NOT NULL,因此不允许声明。(如果你问我,这是一个错误,但是......)。在这种情况下,无论如何都不会在有效值列表中出现NULL,这不会造成很大的损失。

CREATE DOMAIN test_outcome AS
    citext
   -- NOT NULL
    CONSTRAINT test_outcome_legal_values
        CHECK(
            VALUE IN ('pass','warning','fail')
     );

这个想法是创建一个测试项目数组并迭代该数组,将每个值分配给声明的域变量并捕获任何异常。请注意,这部分位于内部 begin...end 块中。这可以防止在生成错误时终止脚本。对于这种类型/级别的测试,我喜欢记录成功的测试以及失败的测试,因此我也会对这些测试进行加薪通知。

do $$
declare 
   -- list items to be tested
   test_set text[] = $Q${warning,Fail,pass,WARNING,FAIL,null,'',foo}$Q$;

   -- define variable of data type being testes
   indx_val test_outcome;

   -- variable to contain text value 
   indx     text;
begin
    -- loop through test set, 
    -- Note the index variable must of same base type as array
    foreach indx in array test_set
    loop

        begin 
            indx_val = indx;  -- assign test 
            raise notice 'Testing: <%>. Successful.',indx;

            -- capture error in assign above
            exception when others then           
                raise notice 'Testing: <%>. Failed.',indx;
                raise notice '  *Error Name:%',  sqlerrm;
                raise notice '  *Error State:%', sqlstate;
        end ; 
    end loop;

exception when others then
      raise notice 'Error Name:%',  sqlerrm;
      raise notice 'Error State:%', sqlstate;
END;
$$;  

您应该能够适应这种通用格式的其他类型定义。祝你好运!


推荐阅读