Skip to content

Conversation

@v-maliutin
Copy link

I developed some functions to make writing tests easier. There are examples in the source code. Also, I wrote an article on habr. Here it is https://habr.com/ru/companies/gnivc/articles/877314/. I know it is in Russian, but hope modern translation will help.
Anyway such functionality is in any modern language and wide known. I just bringing it in PG world.
One more thing. I am going to introduce my work and pgTap at pgConf in Moscow on March 31 2025.

@v-maliutin
Copy link
Author

@theory Hi! Could you please let me know what you think about my PR. I'd appreciate it.

@theory
Copy link
Owner

theory commented May 22, 2025

Sorry, @v-maliutin, hyper busy rn, but will get to it.

@jnasbyupgrade
Copy link

Not a full review, but a couple comments:

AFAIK, there's no reason to modify the unpackaged script.

Instead of building a function body via ||, I think it would be a lot clearer to use format().

@v-maliutin
Copy link
Author

Not a full review, but a couple comments:

AFAIK, there's no reason to modify the unpackaged script.

Instead of building a function body via ||, I think it would be a lot clearer to use format().

@jnasbyupgrade thank you for your review. Rolled back changes in Unpackaged
Regarding format vs ||. May I stay as is? Just I always lost in '%1L, %2I, %3s'. Especially when there are a lot of %. Anyway I can fix it if you insist. This is not a big problem for me.

Copy link
Owner

@theory theory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks super interesting, though I'm not sure they need to be procedures. I requested some change, but the big thing that's missing here is documentation. It would be super helpful for comments in the code to explain what each bit is doing and why (primary example, when it creates two mock functions without explanation). But also the new features should be documented in doc/pgtap.mmd, perhaps with a tutorial.

@v-maliutin v-maliutin requested a review from theory October 25, 2025 11:49
@v-maliutin
Copy link
Author

@theory

Hi, I am going to implement the following features. Please let me know if you think they are a good idea too.

  1. Spy on a routine. This feature would log parameter values.
  2. Spy on a table. A trigger logging inserted/updated/deleted values. Something like a profiler.
  3. Make the output of runtests a standard dataset. It would help to write a tool running tests. Let's say a plugin to DBeaver.
  4. Mocking of procedures.
  5. Special mock to arrange a profiler feature

Copy link
Owner

@theory theory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly this is a huge feature that I think should probably be its own extension, either distributed separately and depending on pgtap (perhaps a release that includes changes to tap_funky that it requires) or else a separate extension as part of the pgTAP distribution. I'm leaning toward the former, at least as you work through the process, because I'm not sure I have the capacity to take on maintaining such a huge feature I don't use. I'm happy to review code and make recommendations if you decide to distribute it as its own extension.

Mocking, faking and making your test independent
================================================

Examples of implementing mocking and faking functionality can be found in my fork [`on GitHub`](https://github.com/v-maliutin/pgtap/tree/examples_forking_and_mocking/examples).
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For permanent documentation I wouldn't refer to "my fork", just link to the source.


Let's say we have a main table and a subordinate table.

CREATE TABLE master(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid the term "master"; how about "parent"?


### `fake_table()` ###

PERFORM fake_table( :_table_ident, :_make_table_empty, :_leave_primary_key, :_drop_not_null, :_drop_collation, :_drop_partitions );
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of the existing doc params have underscores; please remove them.

**Parameters**

`:_table_ident`
: Text array of tables to be faked in the format 'my_schema.my_table'. Required.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this param support multiple tables but the rest refer to a single table?

_drop_collation => false
);

One note. The parameters _leave_primary_key and _drop_not_null are currently contradictory.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use backticks for parameter names.

Comment on lines +11609 to +11613
_func_schema text
, _func_name text
, _func_args text
, _return_set_value text default null
, _return_scalar_value anyelement default null::text
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove leading underscores.

return query execute _query(_name);
end;
%4$sfunction%4$s;',
_func_schema/*1*/, _func_name/*2*/, _func_result_type/*3*/, '$'/*4*/);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it replaces the function in the same schema? I presume you're depending on a transaction ROLLBACK to rollback the mock function, yes?

_func_schema/*1*/, _func_name/*2*/, _func_args/*3*/, _func_result_type/*4*/,
_func_language/*5*/, _return_scalar_value/*6*/, pg_typeof(_return_scalar_value)/*7*/, '$'/*8*/);
execute _mock_ddl;
end if;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like there are some conditions that are ignored here, yes? Should it raise an error for unsupported conditions, e.g., a set-returning C function.

_json text;
_columns text;
--returns a query which you can execute and see your table as normal dataset
--you can find the returned query in the output window in DBeaver, where we see raise notice command output
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what Beaver has to do with this. I have never used it, and it shouldn't be a requirement for users to have it.


CREATE FUNCTION test_faking_functionality() RETURNS SETOF TEXT AS $$
BEGIN
perform fake_table(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of procedures will either require that this functionality not be part of pgTAP or that there be patches to remove it for Postgres versions that don't support it.

@theory
Copy link
Owner

theory commented Nov 1, 2025

@theory

Hi, I am going to implement the following features. Please let me know if you think they are a good idea too.

Seems like it, yes, but again I think this is full-featured enough that it might be better developed and distributed as its own extension.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants