Quantcast
Channel: Testing – Falafel Software Blog
Viewing all articles
Browse latest Browse all 68

3 Tips for Developing Database Tests

$
0
0

I’ve written before about why you should be using Database Projects in your database application, and one of the things I’ve really been delving into is the database tests that they enable. After working with them for a while, I have a few experiences and tips to share.

Setup/Teardown

DBTest01

It’s kind of easy to overlook, but aside from the script used to actually execute your test, you can designate pre-test and post-test scripts to run for individual setup and teardown. However, I feel like setting up data and then writing a separate script to tear it down is a violation of DRY. Instead, I would recommend that you start a transaction within your test script, perform setup there, output results, and then rollback the transaction. For example:

begin tran
set xact_abort on

-- Setup
insert tbl (
    id,
    name
)
values
    (1, 'foo'),
    (2, 'bar'),
    (3, 'etc')

-- Run tests

-- Expect ResultSet 1, Row 1, Column 1 to contain 'bar'
select name
from tbl
where id = 2

-- Teardown
rollback

Nice and simple, no?

Development

I enjoy writing SQL and I also like the VS environment for developing and editing code. And yet, the DB Tests designer surface is so bad. So bad. First reason: Find and Replace doesn’t work. I mean, it’ll come up and look like it’s working. If you’re on autopilot, you might not notice that even though you pressed ctrl+f or ctrl+h for single-file find/replace, it brought up the multi-file version of the window, with the Look in box helpfully set to “All Documents”. First time I ran afoul of this, I had quite a little scare because I long ago unchecked that box that keeps all modified files open. Thankfully, I was still able to undo the unintentional global replacement. You might think, “No problem, just select the text you want to perform the replacement in and then choose the option to replace only within the selection.” So did I, but that option isn’t available when you try to Replace within the DB Test designer. So Find and Replace is crippled within the designer surface. What I do instead is do my development in a tab in SSMS and then copy the finished test script into the designer afterwards. If I’m developing and refining another database object (like a stored procedure or view), I’ll have that open in another tab in SSMS and copy it into the related script in the database project afterwards, too.

Faster setup of test conditions

The other way that the designer surface sucks is that it’s really painfully slow to enter test conditions because of how much switching back and forth between mouse and keyboard you have to do. It’s fine for just one or two, but for bigger tests it’s just awful. Thankfully, the same tricks you might have used back in the bad old days of WebForm designers will still work here. Set up one test condition how you like it, then press F7 to switch to Code View and navigate to the InitializeComponent() method. There’s a comment there warning you not to modify it, but what it really means to say is that the code there is read by and written to by the designer, so don’t put anything in there that can’t be parsed by the designer. In this case, we just want to add some test conditions by editing text instead of clicking a UI and the designer will be none the wiser. In general, adding a test condition in code requires the following steps:

  1. Declare the variable with its fully qualified type name
  2. Initialize it with a parameterless constructor
  3. Configure its properties
  4. Add it to the test’s Conditions collection

You can use the one test condition you set up as a useful way to find all the necessary bits of code and use them as a template. The designer tends to perform these steps all in big blocks, i.e. declare all variables together, initialize them all together, etc, but it doesn’t appear to require this. You can append some code to the end of the InitializeComponent method that performs all these steps for a single new test condition and the designer will parse it successfully. In fact, in light of my recent post on snippets, this seems like an excellent candidate for creating one! I used the Snippet Designer’s “Export as Snippet” context menu option as a starting point.

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
      <Title>DB Scalar Value Condition</Title>
      <Author>adam@falafel.com</Author>
      <Description>DB Scalar Value Condition</Description>
      <HelpUrl>
      </HelpUrl>
      <Shortcut>dbsvc</Shortcut>
    </Header>
    <Snippet>
      <Declarations>
        <Literal Editable="true">
          <ID>variableName</ID>
          <ToolTip>Variable Name</ToolTip>
          <Default>TestCondition</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>columnNumber</ID>
          <ToolTip>Column Number</ToolTip>
          <Default>1</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>expectedValue</ID>
          <ToolTip>Expected Value</ToolTip>
          <Default>expected</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>nullExpected</ID>
          <ToolTip>Null Expected</ToolTip>
          <Default>false</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>resultSet</ID>
          <ToolTip>Result Set</ToolTip>
          <Default>1</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>rowNumber</ID>
          <ToolTip>Row Number</ToolTip>
          <Default>1</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>testName</ID>
          <ToolTip>Test Name</ToolTip>
          <Default>DBTest</Default>
          <Function>
          </Function>
        </Literal>
      </Declarations>
      <Code Language="csharp" Delimiter="$"><![CDATA[Microsoft.Data.Tools.Schema.Sql.UnitTesting.Conditions.ScalarValueCondition $variableName$;
$variableName$ = new Microsoft.Data.Tools.Schema.Sql.UnitTesting.Conditions.ScalarValueCondition();
$variableName$.ColumnNumber = $columnNumber$;
$variableName$.Enabled = true;
$variableName$.ExpectedValue = "$expectedValue$";
$variableName$.Name = "$variableName$";
$variableName$.NullExpected = $nullExpected$;
$variableName$.ResultSet = $resultSet$;
$variableName$.RowNumber = $rowNumber$;
$testName$.Conditions.Add($variableName$);]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

To use, save as a .snippet file in one of the places VS scans for snippets, then just go to the end of the InitializeComponent block in the Database Test code-behind and type “dbsvc+tab+tab” to expand the snippet. This particular snippet creates a Scalar Value Condition test.

Are you using Database Tests? What tips can you share to get the most out of them?

The post 3 Tips for Developing Database Tests appeared first on Falafel Software Blog.


Viewing all articles
Browse latest Browse all 68

Trending Articles