简体   繁体   中英

Writing basic test code for my Postgres objects

I'd like to build up some test code for various objects in my Postgres 11.5 database, and am wondering if there is a straightforward way to implement simple checks in straight SQL. As an example, I've got a simple domain that accepts any of three values, case-blind. This is just one example I've picked because the test cases are finite and simple.

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.';

Below are some simple test statements that exercise good and bad values:

-- 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;

What I'd like to do, is get a single line for each case, and not blow up on an error. I've tried using a DO block, and could use a PL/PgSQL function. Here's the DO code I've tried:

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$

What I get back are a couple of notices. I can't tie those back to the specific statement, as far as I can tell, and I get nothing for success cases.

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

I've seen that there are some unit testing frameworks for PG around, using languages we don't use. Is there any way to do simple tests like the ones above in straight SQL or PL/PgSQL?

There is nothing that I know of, but perhaps the following can provide a template for you.
I needed to modify your domain definition slightly removing the NOT NULL constraint in it. The script below declares a working variable of the test_outcome . However Postgres enforces the NOT NULL thus not allowing the declaration. (A bug if you ask me, but ...). In this case not a great loss as NULL in not in the list of valid values at any rate.

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

The idea is to create an array of test items and iterate that array assigning each value to the the declared domain variable and capture any exception. Note this part is within an inner begin...end block. That prevents script termination when the errors are generated. For this type/level of testing I like to record successful test as well as failures so I have a raise notice for those as well.

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;
$$;  

You should be able to adapt this general format other type definitions. Good Luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM