Adding Console Output to Load Tests running Unit Tests

VSTS allows you to use the Console.WriteLine within unit tests, but the output is only valid when doing a single pass of the unit test. When running the unit test in a load test, there is no built in mechanism for outputting comments or data. The following routines will allow you to track custom messages. It requires you to make some modifications to the LoadTest database and then add the appropriate code to your unit tests.

Modifying the LoadTest Database

Use the following SQL code to generate the table used to store your information:

 

USE [LoadTest]

GO

/****** Object: Table [dbo].[LoadTestConsoleOutput] Script Date: 01/09/2008 08:24:16 ******/

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE TABLE [dbo].[LoadTestConsoleOutput](

       [LoadTestRunId] [int] NULL,

       [AgentId] [int] NULL,

       [UserId] [int] NULL,

       [IterationId] [int] NULL,

       [ScenarioName] [nchar](64) NULL,

       [MessageText] [text] NULL

) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

 

Next, locate the stored procedures that are already built into the LoadTest database. In the Stored Procedure dbo.Prc_DeleteLoadTestRun, add the following line just above the END keyword:

DELETE FROM LoadTestConsoleOutput WHERE LoadTestRunId = @LoadTestRunId

 

This line will allow VSTS to automatically delete any messages you added for a given test pass whenever you delete the test pass in the GUI.

Building the Code to Do the work

The following two methods and associated properties do the brunt of the work. Add these to your test class:

 

        public int userId;

        public int LoadTestRunId;

        public int iteration;

        public int agentId;

        public string scenarioName;

        public bool bWriteConsoleOutput;

        public SqlConnection _Outputconnection;

 

        public void SetupConsoleOutput()

        {

            if (this.TestContext.Properties.Contains("$LoadTestUserContext"))

            {

                // This case occurs when the unit test is run inside a load test

                // Get the LoadTestUserContext

                SqlDataReader reader;

                SqlCommand cmd;

 

                LoadTestUserContext loadTestUserContext = this.TestContext.Properties["$LoadTestUserContext"] as LoadTestUserContext;

 

                cmd = new SqlCommand();

                cmd.Connection = _Outputconnection;

                cmd.CommandType = CommandType.Text;

                cmd.CommandText = "SELECT MAX(LoadTestRunId) AS RunId FROM LoadTestRun";

                reader = cmd.ExecuteReader();

                reader.Read();

                LoadTestRunId = Convert.ToInt32(reader["RunId"]);

                reader.Dispose();

 

 

                // Get MyUserData object from the LoadTestUserContext object, or create and add it if not already there

                userId = loadTestUserContext.UserId;

                iteration = loadTestUserContext.CompletedTestCount;

                agentId = Convert.ToInt32(this.TestContext.Properties["AgentId"]);

                scenarioName = loadTestUserContext.ScenarioName;

                bWriteConsoleOutput = false;

 

            }

            else

            {

                userId = 0;

                iteration = 0;

                agentId = 0;

                scenarioName = "UnitTest";

                bWriteConsoleOutput = true;

            }

        }

 

        public void WriteConsoleOutput(string sMessage)

        {

            if (bWriteConsoleOutput)

                Console.WriteLine(sMessage);

            else

            {

                //setup the database connection to store the output

                SqlCommand cmd;

                cmd = new SqlCommand();

                cmd.Connection = _Outputconnection;

                cmd.CommandType = CommandType.Text;

                cmd.CommandText = "INSERT INTO LoadTestConsoleOutput VALUES ('" +

                    Convert.ToString(LoadTestRunId) + "', '" +

                    Convert.ToString(agentId) + "', '" +

                    Convert.ToString(userId) + "', '" +

                    Convert.ToString(iteration) + "', '" +

                    scenarioName + "', '" +

                    sMessage + "')";

                cmd.ExecuteNonQuery();

                cmd.Dispose();

            }

        }

 

 

 

Next, add the following using declaration at the top of your code:

 

    using Microsoft.VisualStudio.TestTools.LoadTesting;

 

Now you can initialize and use the code. Do this within the actual test method:

 

        [TestMethod()]

        public void DepositApprovals()

        {

              ...

_Outputconnection = new SqlConnection(@"Data Source=collection;

Integrated Security=SSPI;Initial Catalog=LoadTest;

Application Name=DepositApprovals");

            _Outputconnection.Open();

            SetupConsoleOutput();

              ...

              ...

              //Do some work. Call the below statement each time

              //You want to add a comment

            WriteConsoleOutput("This is a message for Blah");

              ...

              ...

            _Outputconnection.Dispose();

        }

 

You need to open and close the connection for each test iteration. The code will automatically detect if you are running a unit test by itself or as a load test. If this is a single unit test, the routine uses Console.WriteLine, but if you are running a load test, the routine will use the LoadTest database.

Thanks to Geoff Gray of Microsoft Testing Services Labs (https://www.microsoft.com/services/microsoftservices/default.mspx) for providing input to this article.