Faking Views

2009-11-09 - General

We've seen FakeTable in tSQLt in action in a few demos now. Did you know that you can use FakeTable to fake a view?

You use FakeTable on a table when you want to test a procedure (or function or view) that relies on a table. It prevents you from needing to concern yourself with all of the other constraints a table might have, such as foreign keys to other tables or not-nullable columns which have nothing to do with your procedure. This is particularly useful if you have a schema where many tables are interrelated through foreign keys because you can focus on the procedure you're testing instead of trying to create test data for dozens of unrelated tables.

Similarly, you would want to fake views. A procedure that uses a view, for example, shouldn't care about how the view got the data, only that it did (at least at the unit test level). For example, a view may join together and filter data and perform some calculations. It is useful to unit test this behavior in isolation. Likewise, it is useful to unit test the functionality of the procedure in isolation from the view's functionality. You can simply call FakeTable and pass a schema name and view name instead of a table name:

EXEC [tSQLt].[FakeTable] 'HumanResources', 'RetiredEmployee';

Then you can insert records directly into the faked view without worrying about all the dependencies of the view or it's underlying tables.

Except for one problem...Sometimes when parsing your T-SQL code, SQL Server will attempt to determine if you are trying to insert into a non-updatable view. A non-updatable view is one where SQL Server cannot use the view definition to accurately decide how to create or update records in the underlying tables. While parsing, SQL Server does not recognize, that FakeTable is replacing your view with a table; even though this works just fine at run-time.

To get around this, the latest version of tSQLt provides two new procedures: SetFakeViewOn and SetFakeViewOff. You place a call to SetFakeViewOn at the very top of your file that defines your test procedures. You place a call to SetFakeViewOff at the very bottom of your file. Both procedures take the schema name for the views you want to fake as a parameter.

For example, suppose the RetiredEmployee view is non-updatable:

EXEC [tSQLt].[SetFakeViewOn] 'HumanResources';

GO

EXEC [tSQLt].[NewTestClass] 'HRTests';

GO

CREATE PROCEDURE [HRTests].[test that GetRetiredEmployeeCount returns number of retired employees]

AS

BEGIN

EXEC [tSQLt].[FakeTable] 'HumanResources', 'RetiredEmployee';

INSERT INTO [HumanResources].[RetiredEmployee] (id) VALUES (1);

INSERT INTO [HumanResources].[RetiredEmployee] (id) VALUES (2);

INSERT INTO [HumanResources].[RetiredEmployee] (id) VALUES (3);

DECLARE @count INT;

SELECT @count = [HumanResources].[GetRetiredEmployeeCount]();

EXEC [tSQLt].[AssertEquals] 3, @count;

END;

GO

EXEC [tSQLt].[SetFakeViewOff] 'HumanResources';

GO

SetFakeViewOn creates an instead-of trigger on all views in the given schema, allowing the compilation of your test cases which modify the contents of the faked view. However, what this has done is modify your schema - it has changed your system under test in a potentially unsafe way.

SetFakeViewOff restores balance to the force. It removes the instead-of triggers right after your test cases are compiled. This means, that your system is back in a good state before you run your tests.

All of the run test procedures have been enhanced to check that SetFakeViewOff has been called appropriately. If it was not called, then tSQLt will raise an error and your test cases will not complete successfully.

Categories: General

3 Responses to Faking Views

  1. Pingback: Advanced Database Unit Testing with tSQLt – Testing cross-database tables

Leave a Reply