Visual Studio 11 database projects and Unit Testing SQL Server database

Please find the slides and demos for the session I presented at Microsoft User Group Hyderabad(MUGH). The agenda of the session was

  • Overview about Database Projects
  • Database development with SQL Server Data Tools(Code-named Juneau)
  • DEMO – Database development using SQL Server Data Tools and Visual Studio 11
  • Basics of Database Unit Testing
  • DEMO – Unit Testing Visual Studio 2010 Database projects

Download from

Utility to generate Word documents from templates using Visual Studio 2010 and Open Xml 2.0 SDK – Part 4

[Update: The source code has been updated to Visual Studio 2017 and DocumentFormat.OpenXml 2.8.1You can download the code from GitHub.]

This is the fourth part of this series. The code is available for download at http://worddocgenerator.codeplex.com/.

In Part 1 I discussed about

  • Document generation using Content Controls and Open XML 2.0 SDK
  • Creating Word templates
  • Implementation and Samples

In Part 2 I discussed about

  • List of functionalities that can be achieved using the utility/source code
  • Description regarding Samples provided with utility
  • New samples added in this update

In Part 3 I discussed about

  • Document-level customizations for Word 2007 and Word 2010
  • One of the ways to “Refresh the document from within the Word(e.g. right click on document and click Refresh) using document-level customizations for Word 2007 and Word 2010“

This post will focus on Charts. I’ve added the samples to generate/refresh charts using OpenXML. The screenshot below displays the template having Scatter chart and Line chart and the document generated out of this template using this utility.

Word 2010 Template having Charts –> Generated documents with Charts refreshed:

image

image

Code Changes:

Class diagram for Chart specific classes is displayed below

image

“SampleDocumentWithTableAndChartsGenerator” is the sample that shows how to refresh template having Scatter and Line charts. The code snippets are displayed below

  • “RefreshCharts” method is added to DocumentGenerator class
/// <summary>

/// Refreshes the charts.

/// </summary>

/// <param name="mainDocumentPart">The main document part.</param>

protected virtual void RefreshCharts(MainDocumentPart mainDocumentPart)

{


}

  • “SampleDocumentWithTableAndChartsGenerator” class overrides “RefreshCharts” method
/// <summary>

/// Refreshes the charts.

/// </summary>

/// <param name="mainDocumentPart">The main document part.</param>

protected override void RefreshCharts(MainDocumentPart mainDocumentPart)

{

    if (mainDocumentPart != null)

    {

        foreach (ChartPart chartPart in mainDocumentPart.ChartParts)

        {

            Chart chart = chartPart.ChartSpace.Elements<Chart>().FirstOrDefault();


            if (chart != null)

            {

                DocumentFormat.OpenXml.Drawing.Charts.ScatterChart scatterChart = chart.Descendants<DocumentFormat.OpenXml.Drawing.Charts.ScatterChart>().FirstOrDefault();

                DocumentFormat.OpenXml.Drawing.Charts.Line3DChart lineChart = chart.Descendants<DocumentFormat.OpenXml.Drawing.Charts.Line3DChart>().FirstOrDefault();


                if (scatterChart != null)

                {

                    ScatterChartEx chartEx = new ScatterChartEx(chartPart, this.scatterChartData);

                    chartEx.Refresh();

                }


                if (lineChart != null)

                {

                    Line3DChartEx chartEx = new Line3DChartEx(chartPart, this.lineChartData);

                    chartEx.Refresh();

                }

            }


            chartPart.ChartSpace.Save();

        }

    }

}

  • Refresh method is defined in ChartEx<T>
/// <summary>

/// Refreshes this instance.

/// </summary>

public void Refresh()

{

    ChartData chartData = this.GetChartData();


    if (chartData != null && chartData.IsValid())

    {

        string sheetName = this.UpdateEmbeddedObject();


        Chart chart = chartPart.ChartSpace.Elements<Chart>().FirstOrDefault();


        if (chart != null)

        {

            this.UpdateChart(chart.Descendants<T>().FirstOrDefault(), sheetName);

        }

    }

}

For complete code download the source code.

Summary:

Please provide feedback/comments and I’ll try to incorporate most of them in new releases.

How to use Pex and Moles to generate unit tests for a project having external dependency(WCF Proxy) using Visual Studio 2010 SP1

Source Code:

In this post I’ll discuss about writing unit tests using Pex and Moles. Pex and Moles are Visual Studio 2010 Power Tools that help Unit Testing .NET applications.

  • Pex automatically generates test suites with high code coverage. Right from the Visual Studio code editor, Pex finds interesting input-output values of your methods, which you can save as a small test suite with high code coverage.
  • Moles allows to replace any .NET method with a delegate. Moles supports unit testing by providing isolation by way of detours and stubs i.e. Generate a Mole type from the original type and redefine its behavior using delegates.

Pex and Moles can be downloaded from http://research.microsoft.com/en-us/projects/pex/.

I’ll explain the steps to generate unit tests for a project which calls a WCF service. Pex will be used to generate unit tests. Moles will be generated to isolate the external dependency(WCF proxy) and behavior will be redefined using delegates.

The projects inside the sample solution are

  1. DemoService: This project is a WCF Service.
  2. DemoLibrary: This project is a Class library and service reference to DemoService has been added. Unit tests will be generated for this project.
  3. ConsoleApp: This project is a Console application.
  4. DemoLibrary.Tests: This is a Test project and contains unit tests for DemoLibrary.

The solution structure is displayed below

image

DemoLibrary calls DemoService though proxy as displayed in the Layer diagram

image

I’ll now discuss in brief the code snippets of each project

WCF Service(DemoService): This service provided only a single operation

[ServiceContract]

public interface IDemoService

{

    [OperationContract]

    string Search(string criteria);

}

WCF Service Client(DemoLibrary): It calls the Search method of DemoService through proxy as displayed below

public string GetResults(string s)

{

    DemoServiceReference.DemoServiceClient client = null;

 

    try

    {

        client = new DemoServiceReference.DemoServiceClient();

        client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;                

        client.ChannelFactory.Credentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;

        s = client.Search(s);

        return s;

    }

    finally

    {

        if (client != null)

        {

            if (client.State == CommunicationState.Opened)

            {

                client.Close();

            }

            else if (client.State == CommunicationState.Faulted)

            {

                client.Abort();

            }

        }

    }

}

Unit Testing DemoLibrary using Pex and Moles:

In order to generate unit tests for WCF Service Client(DemoLibrary) project the steps are

  1. Right click on the class for which unit tests needs to be generated and click “Create Parameterized Unit Tests” as displayed belowimage
  2. A popup will be displayed where Filters and Output can be modified. Click Ok to go to next step.image
  3. A new test project will be created. Test Class and Test stub will be be added to this project as displayed below
    /// <summary>This class contains parameterized unit tests for Search</summary>

    [PexClass(typeof(Search))]

    [PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))]

    [PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentException), AcceptExceptionSubtypes = true)]

    [TestClass]

    public partial class SearchTest

    {

        /// <summary>Test stub for GetResults(String)</summary>

        [PexMethod]

        public string GetResults([PexAssumeUnderTest]Search target, string s)

        {

            string result = target.GetResults1(s);

            return result;

            // TODO: add assertions to method SearchTest.GetResults(Search, String)

        }

    }

  4. There is an external dependency(GetResults makes a service call though the WCF Proxy) so “Run Pex Explorations” will not generate unit tests as displayed below                                                                          image
  5. In order to isolate the external dependency we need to generate Moles before running Pex Explorations. Moles will be generated for DemoLibrary and System.ServiceModel assemblies and behavior will be redefined using delegates. There are two ways to generate a mole for an assembly. I’ll show you both the approaches
    1. Visual Studio: This is the easiest way.
      1. Right click on the reference and generate Moles for that assembly as displayed below.image
      2. A .Moles file will be added to the project. Build the project and Moles.dll will be added to MolesAssemblies folder as displayed below                                                                                 .image
    2. Command Prompt: Moles can be generated from the command prompt.
      1. Run the moles.exe and specify the assembly path for which Moles needs to be created.image_thumb2[1]
      2. Copy the generated assembly to the Project and add reference to it.
  6. Similarly as explained above we need to generate Moles for System.ServiceModel assembly. For Visual Studio 2010 SP1 this may fail with error message “The type or namespace name ‘IHttpCookieContainerManager’ does not exist in the namespace ‘ssm::System.ServiceModel.Channels’ (are you missing an assembly reference?)”. This step however works fine for Visual Studio 2010. The fix is to exclude the type i.e. ‘IHttpCookieContainerManager’ from StubGeneration as displayed belowimage
  7. The next step is to Mock the Service call(redefine behavior using delegates) and add Asserts as displayed in code snippets below
    /// <summary>Test stub for GetResults(String)</summary>

    [PexMethod]

    public string GetResults([PexAssumeUnderTest]Search target, string s)

    {

        MockWCFService<IDemoService>();

     

        MDemoServiceClient.Constructor = (var1) =>

           new MDemoServiceClient { };

     

        MDemoServiceClient.AllInstances.SearchString = (var1, var2) =>

        {

            return "Result";

        };

     

        string result = target.GetResults(s);

        PexAssert.IsNotNullOrEmpty(result);

        PexAssert.AreEqual(result, "Result");

        return result;            

    }

     

    /// <summary>

    /// Mocks the WCF service.

    /// </summary>

    private void MockWCFService<TService>() where TService : class

    {

        MClientCredentials.Constructor = (var1) =>

            new MClientCredentials()

            {

                WindowsGet = () => { return new MWindowsClientCredential(); }

            };

     

        MClientCredentials.AllInstances.WindowsGet = (var1) =>

        {

            return new MWindowsClientCredential();

        };

     

        MWindowsClientCredential.AllInstances.ClientCredentialGet = (var1) =>

        {

            return new System.Net.NetworkCredential();

        };

     

        MWindowsClientCredential.AllInstances.ClientCredentialSetNetworkCredential = (var1, var2) => { };

     

        MWindowsClientCredential.AllInstances.AllowNtlmGet = (var1) => { return true; };

     

        MWindowsClientCredential.AllInstances.AllowNtlmSetBoolean = (var1, var2) => { };

     

        MWindowsClientCredential.AllInstances.AllowedImpersonationLevelGet = (var1) => { return System.Security.Principal.TokenImpersonationLevel.Impersonation; };

     

        MWindowsClientCredential.AllInstances.AllowedImpersonationLevelSetTokenImpersonationLevel = (var1, var2) => { };

     

        MChannelFactory.AllInstances.CredentialsGet = (var1) => { return new MClientCredentials(); };

     

        MClientBase<TService>.AllInstances.ClientCredentialsGet = (var1) =>

        {

            return new System.ServiceModel.Description.ClientCredentials();

        };

     

        MClientBase<TService>.AllInstances.ChannelFactoryGet = (var1) =>

        {

            return new MChannelFactory01<TService>();

        };

     

        MClientBase<TService>.AllInstances.StateGet = (var1) =>

        {

            return PexChoose.EnumValue<CommunicationState>("CommunicationState");

        };

     

        MClientBase<TService>.AllInstances.Close = (var1) =>

        { };

     

        MClientBase<TService>.AllInstances.Abort = (var1) =>

        { };              

    }

  8. Run Pex Explorations to generate unit tests for GetResults method as displayed below image
  9. Unit tests will be added to the Test Class as displayed below                      image
  10. Go to Test View and Run the unit tests as displayed below                  image

 

Summary:

In a similar way we can extract out external dependencies using Moles and then run Pex Explorations. A few examples of external dependencies can be data layer, UI layer, server calls etc. You can read more about Pex and Moles at http://research.microsoft.com/en-us/projects/pex/.

Utility to generate Word documents from templates using Visual Studio 2010 and Open Xml 2.0 SDK – Part 3

[Update: The source code has been updated to Visual Studio 2017 and DocumentFormat.OpenXml 2.8.1You can download the code from GitHub.]

This is the third post of this series. The earlier posts can be read at Part 1 and Part 2. The code is available for download at Utility Source Code.

In Part 1 I discussed about

  • Document generation using Content Controls and Open XML 2.0 SDK
  • Creating Word templates
  • Implementation and Samples

In Part 2 I discussed about

  • List of functionalities that can be achieved using the utility/source code
  • Description regarding Samples provided with utility
  • New samples added in this update

In this part I’ll discuss about the sample that shows one of the ways to “Refresh the document from within the Word(e.g. right click on document and click Refresh) using document-level customizations for Word 2007 and Word 2010“. On click of Refresh Document the content of the document is refreshed as displayed below

image

Project “WordDocumentGenerator.WordRefreshableDocumentAddin” has been added to the utility for this sample. The steps followed for creating this sample are listed below

  1. Added a new Word 2010 Document project as displayed below image
  2. Updated the document by adding the content controls as displayed below image
  3. Added a new Command bar button i.e. “Refresh Data” to the Command bar. On click of this button the document will be refreshed. The common scenario will be to refresh data from the Service. “WordDocumentGenerator.WordRefreshableDocumentAddin” is the document level customization project. This project references “WordDocumentGenerator.Library” and “WordDocumentGenerator.Client” projects.

The code snippet to add a new Command bar button is

/// <summary>

/// Adds the command bar.

/// </summary>

/// <param name="cmdBr">The CMD br.</param>

/// <param name="handler">The handler.</param>

/// <param name="index">The index.</param>

/// <param name="tag">The tag.</param>

/// <param name="caption">The caption.</param>

/// <returns></returns>

private CommandBarButton AddCommandBar(CommandBar cmdBr, _CommandBarButtonEvents_ClickEventHandler handler, int index, string tag, string caption)

{

    CommandBarButton cmdBtn = (CommandBarButton)cmdBr.FindControl(MsoControlType.msoControlButton, 0, tag, missing, missing);


    if ((cmdBtn != null))

    {

        cmdBtn.Delete(true);

    }


    cmdBtn = (CommandBarButton)cmdBr.Controls.Add(MsoControlType.msoControlButton, missing, missing, index, true);

    cmdBtn.Style = MsoButtonStyle.msoButtonCaption;

    cmdBtn.Caption = caption;

    cmdBtn.Tag = tag;

    cmdBtn.Visible = true;


    cmdBtn.Click -= handler;

    cmdBtn.Click += handler;


    if (!commandBarsTags.Contains(tag))

    {

        commandBarsTags.Add(tag);

    }


    return cmdBtn;

}

On click of refresh data the main steps are

1. Get package steam from the document

Microsoft.Office.Interop.Word.Document doc = app.ActiveDocument;


// Get the active documents as stream of bytes

byte[] input = doc.GetPackageStream();

2. Call the Service/Client method that generates/refreshes the document. This can be a Server or a direct call. In this method it’s a direct call.

// Generate document on the Server. AddInService can be a proxy to service, however here it's direct call

byte[] output = AddInService.GenerateDocument(input);

/// <summary>

/// Generates the document.

/// </summary>

/// <param name="documentStream">The document stream.</param>

/// <returns></returns>

public static byte[] GenerateDocument(byte[] documentStream)

{}

3. Update the document contents

XDocument xDoc = OPCHelper.OpcToFlatOpc(wordDocument.Package);

string openxml = xDoc.ToString();

doc.Range().InsertXML(openxml);

These are partial code snippets to show the code flow. For complete sample please download the source code.

References:

How to unit test SQL Server 2008 database using Visual Studio 2010

In this article I’ll discuss about unit testing SQL Server 2008 Database project using Visual Studio 2010. As Unit tests test the part of the program integration testing becomes easier, moreover unit tests help enhancing, maintaining or extending a solution provided they are well written. This is first part of this series “How to unit test SQL Server 2008 database using Visual Studio 2010”. The next parts of this series are

Unit test SQL Server 2008 – Part 2 – Focuses on internals of database unit testing i.e. assemblies

Unit test SQL Server 2008 – Part 3 – Focuses on data generation, schema comparison, data comparison and data driven unit tests

There is no use to write an unit test badly as later on maintainability of the solution suffers. It either has to be a good unit test or no test at all. It’s better to eliminate bugs early rather than late and that is where unit tests wins. Secondly they can be fully automated and ideally should be.

Assuming a team is developing a solution and no unit testing is introduced. After 2 weeks they realize that some bugs have been introduced into the system. Now in order to find and fix these the team

  1. needs to track all the changes to find when it got introduced
  2. check for the features that are dependent and fix them
  3. it may happen and to be true happens most of the time that the other features implemented though working fine may break with the fix that will be applied to close these bugs e.g. initial state of the code is S1. Developer A checks in that code and now state is S2. Developer B fixes some bug that was there in S1. As Developer B is working on codebase S2 so after he fixes the bug the state of code is S3. It was reported that there was an bug in changes Developer A made. Now as Developer B has checked in on state S2 and if those depend on Developer A changes that means after Developer A will fix his part, Developer B changes will break. See how much havoc it can create as here I considered only 2 check ins and 2 Developers.

This is where the power of writing good unit tests kick in. This ripple effect of bugs had not happened if unit testing framework was incorporated into the system. This adds to the confidence of the team and confidence can have a positive effect beyond the boundaries of the team. The next point is “Is unit testing a overload” and the answer is “No” unless you write bad unit tests.

“With power comes great responsibility” quote from Spiderman movie seems to be the right answer. I can go deep into unit tests but in this article I’ll discuss how we can unit test SQL Server 2008 database using Visual Studio 2010.

There are templates for SQL Server 2005 database project in Visual Studio 2008/2010 but those are out of scope of this article as I have not tried them. They may or may not have the same workflow as discussed later so I will restrict the scope of this article to only VS 2010 and SQL Server 2008.

Software:

VS 2010 Ultimate

SQL Server 2008

Test Data:

In this example as displayed below I will implement unit test for adding a Student i.e. uspAddStudent store procedure. If unit test has to be written for uspAddEventPass stored procedure then we need to set pre-test conditions as it has foreign key relation to Student and Event tables along with the test condition.

image

Please find below the SQL script for creating the test database for unit testing. This script will be imported so please save this to file.

USE [SampleDB]

GO

/****** Object:  Table [dbo].[Event]    Script Date: 07/27/2010 06:20:36 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE TABLE [dbo].[Event](

[EventId] [bigint] IDENTITY(1,1) NOT NULL,

[EventName] [nchar](100) NOT NULL,

CONSTRAINT [PK_Event] PRIMARY KEY CLUSTERED

(

[EventId] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]

GO

/****** Object:  Table [dbo].[Student]    Script Date: 07/27/2010 06:20:36 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE TABLE [dbo].[Student](

[StudentId] [bigint] IDENTITY(1,1) NOT NULL,

[StudentName] [nchar](100) NOT NULL,

CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED

(

[StudentId] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]

GO

/****** Object:  Table [dbo].[EventPass]    Script Date: 07/27/2010 06:20:37 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE TABLE [dbo].[EventPass](

[EventPassId] [bigint] IDENTITY(1,1) NOT NULL,

[EventId] [bigint] NOT NULL,

[StudentId] [bigint] NOT NULL,

CONSTRAINT [PK_EventPass] PRIMARY KEY CLUSTERED

(

[EventPassId] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]

GO

/****** Object:  StoredProcedure [dbo].[uspAddStudent]    Script Date: 07/27/2010 06:20:38 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:        <Author,,Name>

-- Create date: <Create Date,,>

-- Description:    <Description,,>

-- =============================================

CREATE PROCEDURE [dbo].[uspAddStudent]

-- Add the parameters for the stored procedure here

@StudentName nchar(100)

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;


-- Insert statements for procedure here

INSERT INTO [dbo].[Student]

([StudentName])

VALUES(@StudentName)

END

GO

/****** Object:  StoredProcedure [dbo].[uspAddEvent]    Script Date: 07/27/2010 06:20:38 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:        <Author,,Name>

-- Create date: <Create Date,,>

-- Description:    <Description,,>

-- =============================================

CREATE PROCEDURE [dbo].[uspAddEvent]

-- Add the parameters for the stored procedure here

@EventName nchar(100)

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;


-- Insert statements for procedure here

INSERT INTO [dbo].[Event]

([EventName])

VALUES(@EventName)

END

GO

/****** Object:  StoredProcedure [dbo].[uspGetEventDetails]    Script Date: 07/27/2010 06:20:38 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:        <Author,,Name>

-- Create date: <Create Date,,>

-- Description:    <Description,,>

-- =============================================

CREATE PROCEDURE [dbo].[uspGetEventDetails]

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;


-- Insert statements for procedure here

SELECT EP.[EventPassId],EP.[EventId], E.EventName, EP.[StudentId], S.StudentName

FROM [dbo].[EventPass] As EP

INNER JOIN .dbo.Student As S

ON EP.StudentId = S.StudentId

INNER JOIN .dbo.[Event] As E

ON EP.[EventId] = E.[EventId]


END

GO

/****** Object:  StoredProcedure [dbo].[uspAddEventPass]    Script Date: 07/27/2010 06:20:38 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

-- =============================================

-- Author:        <Author,,Name>

-- Create date: <Create Date,,>

-- Description:    <Description,,>

-- =============================================

CREATE PROCEDURE [dbo].[uspAddEventPass]

-- Add the parameters for the stored procedure here

@EventId bigint,

@StudentId bigint

AS

BEGIN

-- SET NOCOUNT ON added to prevent extra result sets from

-- interfering with SELECT statements.

SET NOCOUNT ON;


-- Insert statements for procedure here

INSERT INTO [dbo].[EventPass]

([EventId]

,[StudentId])

VALUES

(@EventId

,@StudentId)

END

GO

/****** Object:  ForeignKey [FK_EventPass_Event]    Script Date: 07/27/2010 06:20:37 ******/

ALTER TABLE [dbo].[EventPass]  WITH CHECK ADD  CONSTRAINT [FK_EventPass_Event] FOREIGN KEY([EventId])

REFERENCES [dbo].[Event] ([EventId])

GO

ALTER TABLE [dbo].[EventPass] CHECK CONSTRAINT [FK_EventPass_Event]

GO

/****** Object:  ForeignKey [FK_EventPass_Student]    Script Date: 07/27/2010 06:20:37 ******/

ALTER TABLE [dbo].[EventPass]  WITH CHECK ADD  CONSTRAINT [FK_EventPass_Student] FOREIGN KEY([StudentId])

REFERENCES [dbo].[Student] ([StudentId])

GO

ALTER TABLE [dbo].[EventPass] CHECK CONSTRAINT [FK_EventPass_Student]

GO

Steps:

Step 1:

Open Visual Studio and create a new SQL Server 2008 Database Project as displayed below

image

Step 2:

Save the test SQL script for on you machine. Right click the project and click import script and import the saved script as displayed below

image

After import is done you will find the schema objects as highlighted below

image

Step 3:

In the Properties –> Deploy tab of the project set

Configure deployment settings for –> My Isolated development environment

Deploy Action –> Create a deployment script(.sql) and deploy to database

Target Connection –> Edit/New connection

Deployment configuration file –> Edit –> Uncheck Block incremental deployment if data loss might occur checkbox

as displayed below

image

Here an isolated development environment is set so that each database developer can make and test changes without affecting other members of the team. The isolated database development environment is based on the database project that contains the definitions for all the objects that are in the production database.

Create a deployment script(.sql) and deploy to database is selected as we want the database project to be deployed for each build configuration.

When you make changes to a database project and deploy them to a database server, some changes can result in data loss from database project being dropped and recreated. Here data loss is allowed as we are working in an isolated development environment on a database that is populated with test data.

Save changes and Build the solution.

Step 4:

Deploy this project as displayed below

image

You can configure the properties as displayed below. If you click Show All files then you can view the files generated e.g. in Debug mode. The connection string that you specified is saved in sql –> debug –> UnitTestDB.deploymanifest

image

Step 5:

I’ll now create database unit tests for the stored procedures. As displayed below go to View –> Database Schema View and then right click the stored procedure for which you want to write unit test and click Create Unit Tests as displayed below.

In case this option is disabled then there must be some issue with the sql file that has been imported and check the Error List for Warnings/Errors e.g. in my case I had specified [Database].[Schema].[Object] in one of the store procedure and though there was warning but I ignored as there were no errors 🙂 and when I tried to create the unit test the option was disabled. The fix was to use [Schema].[Object] as displayed below

image

image

Now select the procedures as displayed below

image

Step 6:

In the configuration dialog for project ‘SampleDBTestProject’ configure options as displayed below

image

The connection string that you specified is saved in the app.config of this project.

Step 7:

Open the SampleDBStoredProcedureUnitTests as displayed below

image

Select dbo_uspAddStudentTest and in Test Conditions remove Inconclusive test condition. If an Inconclusive Test Condition is added to a database unit test, the test will always fail with an Inconclusive result. It’s not a passed result, nor a failed result. It indicates that the results of the test could not be verified. Add Row Count test condition  and set Row Count = 1 as only one row gets added when this store procedure runs as displayed below

image

The snippet is displayed below

-- unit test for dbo.uspAddStudent

DECLARE @RC AS INT, @StudentName AS NVARCHAR (100);


SELECT @RC = 0,

@StudentName = 'Unit Test';


EXECUTE @RC = [dbo].[uspAddStudent] @StudentName;


SELECT * FROM [dbo].[Student];

Step 8:

Go to Test –> Windows –> Test View and select dbo_uspAddEventTest and Run Selection as displayed below.

image

In the Test Results the results of the tests run will be displayed. In case a particular test fails it will display as failed and the reason for failure.

In the same way the unit tests for other stored procedures can be written by specifying the Pre-Test/Test/Post-Test Conditions and Test Conditions.

The link to the next part of this series is Unit test SQL Server 2008 – Part 2

del.icio.us Tags: Visual Studio 2010,SQL Server 2008,Unit Test,Test View,Database Schema View

References: http://msdn.microsoft.com/en-us/library/aa833283.aspx

http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-01-37-36/1351.UnitTestDB.zip