Create your own Test Host using XAML to run your unit tests
A few days ago, somebody came into my office and plopped down a box. It seemed very light. He said that it was a new PC. I thought hmmm…. The box seems empty…Why am I getting a new PC?.
Apparently an inventory was made and my current hardware was at the lower end of the list.
So I started up the Dell Optiplex 755 with 4 gigs of RAM, and it was running Vista 64. Super: I hadn’t done much with 64 bit code yet.
Sure enough, debugging 64 bit native applications shows that the CPU has 64 bit wide registers (and more registers!). If I attach to a 64 bit process, the Debug->Windows->Registers looks like:
RAX = 0000000000000000 RBX = 000000001DEB7818 RCX = 000000000F99A027
RDX = 0000000000000000 RSI = 0000000000000001 RDI = 00000000242E5454
R8 = 000000001FD3FCB8 R9 = 0000000000000000 R10 = 0000000000000000
R11 = 0000000000000206 R12 = 0000000000000000 R13 = 0000000000000000
R14 = 0000000000000000 R15 = 0000000000000000 RIP = 000007FEF0FD3D29
RSP = 000000001FD3FCF0 RBP = 0000000000000000 EFL = 00000246
If I attach to a 32 bit process:
EAX = 00000000 EBX = 006AC138 ECX = 79E74400 EDX = 00000000 ESI = 00DF6700
EDI = 00000000 EIP = 59B80265 ESP = 001DDEE8 EBP = 001DDEE8 EFL = 00000206
001DDEFC = 06CD35C8
(The debugger is pretty amazing!)
The sheer size of the registers means instead of a maximum 2^32 =4 gig virtual address space, we have 2^64
To calculate that, type this in the Fox command window:
?LOG10(2^64)
?2^64
Which shows 19.27, 1.844674E+19
That means 19.27 zeros: 18,000,000,000,000,000,000 which is 18 billion billion or 18 exabytes!
Coincidentally, we have some new 64 bit code that was recently created by “patching” the 32 bit version, and I wanted some test tools for it.
I have a VS Test Project with many (32 bit) tests. (Use Visual Studio Test framework to create tests for your code)
So I created my own Test Host in a day:
This Test Host:
· Uses the existing 32 bit test source code as linked files: if you make changes to the tests, they will automatically be updated in both 32 and 64 bit versions
· Can be built as 32 bit or 64 bit (Project->Properties->Compile->Advanced Compile Options->Target CPU->AnyCPU or x86), so it can run tests in either 32 or 64 bits. When set as AnyCPU and running on 64 bit OS like Vista 64, then it will run as 64 bit.
· Does not require test deployment: you can test in place. VSTestHost requires deployment.
· Uses reflection on itself to get and run the TestInitialize, TestCleanup and TestMethods.
· Can run selected tests in a loop for stress tests, like leak detection.
· Uses XAML and Data Binding (see Create your own media browser: Display your pictures, music, movies in a XAML tooltip)
o Notice how the enabling and disabling of buttons is done via data binding.
o The data binding updates the status (Success,Failure/Pending) and its color in the ListView.
o Shows the test methods in a ListView with click/sort column headers.
· The tests run on a worker thread. The UI is thus responsive and not blocked.
· A progress bar and stopwatch also show
· Can be run without UI: another assembly can call it to run tests
· Can determine if it’s running 64 or 32: IntPtr.Size=8 bytes on 64, 4 bytes on 32.
I’m thinking about adding a new 32 bit test case (for running in the VS IDE) that will launch all the 64 bit tests, or a new one for each of the 32 bit test cases, but that’s lower priority.
This new test host has already helped me find several 64 bit issues.
Follow my prior post: Use Visual Studio Test framework to create tests for your code to create a project. (If you don’t have Fox or Excel, you can either get them or remove the Fox/Excel code in the test)
If you add these lines to the test
System.Diagnostics.Debug.WriteLine("Sizeof IntPtr = " + IntPtr.Size.ToString)
System.Diagnostics.Debug.WriteLine(System.Diagnostics.Process.GetCurrentProcess.MainModule.FileName)
You’ll get the output:
Sizeof IntPtr = 4
C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\vstesthost.exe
Nothing unexpected. VSTestHost is a 32 bit EXE, which means only 32 bit code is run.
To make the test host more interesting, add a few more tests to the bottom of UnitTests1:
Shared oRandom As New Random
<TestMethod()> _
Sub EmptyTest()
End Sub
<TestMethod()> _
Sub AlwaysFail()
Assert.IsTrue(False, "True is never false!")
End Sub
<TestMethod()> _
Sub SometimesFail()
If oRandom.NextDouble < 0.4 Then
Assert.IsTrue(False, "True is never false!")
End If
End Sub
<TestMethod()> _
Sub RarelyFails()
If oRandom.NextDouble < 0.02 Then
Assert.IsTrue(False, "True is rarely false!")
End If
End Sub
To create the Test Host:
Right Click on the Solution from above in Solution explorer, choose Add->New Project. This time choose Windows->WPF Application. Put in a folder next to the folder of the existing test project. I called mine MyTestHost
Right Click on MyTestHost in solution explorer, choose Set As Startup Project. That way, hitting F5 will run this new project.
Delete the Window1.XAML in the solution explorer. We’ll create our own.
Delete MyTestHost->Application.xaml (we have our own Sub Main)
Right Click on MyTestHost in solution explorer, choose Add New Item, Code->Class. Name it MyTestHost.vb
Right Click on MyTestHost in solution explorer, choose Add Existing Item, navigate to the UnitTest1.vb file in the other project. Make sure you add as a Lnked File. The “Add” button on the dialog has a little down arrow that allows you to choose Add As Link.
Note: the Fox code in the unit test TestMethod1 will fail in 64 because there is no 64 bit version of it.
Add references to:
Microsoft.VisualStudio.QualityTools.UnitTestFramework
System.Windows.Forms
There are 3 sections of code to paste below: Window1.XAML, Window1.XAML.VB (the code behind file), and MyTestHost.vb
Hit F5, click on the button to run the tests.
You can force the Testmethod1 to fail simply by forcing Excel to close before it’s done.
See also:
Remove double spaces from pasted code samples in blog
<Window1.XAML code to paste>
<Window x:Class="Window1"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="711" Width="1043">
<Grid DataContext="{Binding}">
<TextBlock Height="21" HorizontalAlignment="Right" Margin="0,12,16,0" Name="tbClock" VerticalAlignment="Top" Width="81" Text="{Binding Path=Clock}"/>
<ListView Margin="22,49,54,90" Name="ListView1" ItemsSource="{Binding Path=TestMethods}" >
<ListView.View>
<GridView >
<GridViewColumn>Selected
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="ChkBox" IsChecked="{Binding Path=Selected}"></CheckBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>Status
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Width="50" Text="{Binding Path=Status}" Foreground="{Binding Path=StatusColor}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>TestName
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=TestName}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>Description
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Description}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>TestClass
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=TestClass}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>mSecs
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=mSecs}" Width="40" HorizontalAlignment="Right"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>ErrorMessage
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ErrorMessage}" ToolTip="{Binding Path=ErrorMessage}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>Owner
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Owner}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>Pri
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Pri}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<Button Height="23" HorizontalAlignment="Left" Margin="22,0,0,35"
Name="btnSelectAll" VerticalAlignment="Bottom" Width="85" ButtonBase.Click="btnClicked">Select_All</Button>
<Button Height="23" HorizontalAlignment="Left" Margin="117,0,0,35"
Name="btnInvertSelection" VerticalAlignment="Bottom" Width="85" ButtonBase.Click="btnClicked">_InvertSelection</Button>
<CheckBox Height="16" HorizontalAlignment="Left" Margin="215,0,0,65"
Name="chkLoopForever" VerticalAlignment="Bottom" Width="120" IsEnabled="{Binding Path=NotIsTestRunning}">_LoopForever</CheckBox>
<Button Height="23" HorizontalAlignment="Left" Margin="215,0,0,35"
Name="btnRunSelected" VerticalAlignment="Bottom" ButtonBase.Click="btnClicked" Width="85" IsEnabled="{Binding Path=NotIsTestRunning}">_RunSelected</Button>
<Button Height="23" HorizontalAlignment="Left" Margin="315,0,0,35"
Name="btnAbortRun" VerticalAlignment="Bottom" ButtonBase.Click="btnClicked" IsEnabled="{Binding Path=IsTestRunning}" Width="56.82">_AbortRun</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,54,35"
Name="btnQuit" VerticalAlignment="Bottom" Width="85" ButtonBase.Click="btnClicked" IsCancel="True">_Quit</Button>
<ProgressBar Height="14" HorizontalAlignment="Right" Margin="0,0,16,0"
Name="ProgressBar1" VerticalAlignment="Top" Width="123" />
</Grid>
</Window>
</Window1.XAML code to paste >
<Window1.XAML.vb code to paste >
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Class Window1
Implements INotifyPropertyChanged ' so XAML UI updates
Private m_TestMethods As ReadOnlyCollection(Of TestItem)
Private m_SelectedTests As New Collection(Of TestItem)
Private m_StatusText As String
Private m_IsTestRunning As Boolean = False
Private m_Clock As String
Private m_nTestPass As Integer
Friend StopWatch As Diagnostics.Stopwatch
Public Property Clock() As String
Get
Return m_Clock
End Get
Set(ByVal value As String)
If m_Clock <> value Then
m_Clock = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Clock"))
End If
End Set
End Property
Public Property IsTestRunning() As Boolean
Get
Return m_IsTestRunning
End Get
Set(ByVal value As Boolean)
m_IsTestRunning = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("IsTestRunning"))
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NotIsTestRunning"))
End Set
End Property
Public ReadOnly Property NotIsTestRunning() As Boolean
Get
Return Not m_IsTestRunning
End Get
End Property
Public Property StatusText() As String
Get
Return m_StatusText
End Get
Set(ByVal value As String)
Dim strTitle = "TestHost "
If IntPtr.Size > 4 Then
strTitle += "amd64 64 bit"
Else
strTitle += "x86 32 bit"
End If
strTitle += " Total Tests = " + TestMethods.Count.ToString
If m_nTestPass > 0 Then
strTitle += " Test Pass #" + m_nTestPass.ToString + " PeakWorkingSet =" + Process.GetCurrentProcess.PeakWorkingSet64.ToString("n0")
End If
m_StatusText = strTitle + " " + value
Me.Title = m_StatusText ' in case of process crash, we can still see window title
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("StatusText"))
End Set
End Property
Public ReadOnly Property TestMethods() As ReadOnlyCollection(Of TestItem)
Get
Return m_TestMethods
End Get
End Property
Sub New(ByVal TestMethods As ReadOnlyCollection(Of TestItem))
InitializeComponent()
m_TestMethods = TestMethods
StatusText = "" ' init window title
Me.ProgressBar1.Visibility = Windows.Visibility.Hidden
Me.ProgressBar1.Minimum = 0
Me.ProgressBar1.Maximum = 100
Me.ProgressBar1.Value = 0
Me.DataContext = Me ' so XAML can databind to our members
AddHandler Me.Closed, AddressOf OnWindowClosed
Me.AddHandler(System.Windows.Controls.GridViewColumnHeader.ClickEvent, New RoutedEventHandler(AddressOf OnHeaderClicked))
End Sub
Sub OnWindowClosed(ByVal sender As Object, ByVal e As EventArgs)
TestItem.ShutDown() ' abort thread
End Sub
Private Sub btnClicked(ByVal sender As System.Windows.Controls.Button, ByVal e As RoutedEventArgs)
Debug.WriteLine((New StackTrace).GetFrame(0).GetMethod.Name + " " + sender.Name)
Select Case CStr(sender.Name)
Case "btnSelectAll"
For Each lstItem In ListView1.Items
Dim tstItem = CType(lstItem, TestItem)
If Not tstItem.Selected Then
tstItem.Selected = True
End If
Next
Case "btnInvertSelection"
For Each lstItem In ListView1.Items
Dim tstItem = CType(lstItem, TestItem)
tstItem.Selected = Not tstItem.Selected
Next
Case "btnRunSelected"
m_SelectedTests.Clear()
m_nTestPass = 1
For Each lstItem In ListView1.Items ' Get the user selected items in display order
Dim tstItem = CType(lstItem, TestItem)
tstItem.Reset() ' reset all to not run yet (doesn't reset checkbox)
If tstItem.Selected Then
m_SelectedTests.Add(tstItem)
tstItem.Status = TestItem.TstStatus.Pending
End If
Next
If Me.chkLoopForever.IsChecked Then
Do While True
DoRunSelected()
For Each lstItem In ListView1.Items
Dim tstItem = CType(lstItem, TestItem)
If tstItem.Status = TestItem.TstStatus.Aborted OrElse tstItem.Status = TestItem.TstStatus.Failed Then
Me.StatusText = String.Format(" Failed {0}", DateTime.Now.ToString)
Exit Do
End If
tstItem.Reset()
Next
m_nTestPass += 1
Loop
Else
DoRunSelected()
End If
Case "btnAbortRun"
TestItem.ShutDown()
For Each tstItem In m_SelectedTests
If tstItem.Status = TestItem.TstStatus.Pending Then
tstItem.Status = TestItem.TstStatus.NotRun
End If
Next
Case "btnQuit"
TestItem.ShutDown()
Me.Close()
Case Else
Debug.Assert(False, "Unhandled button")
End Select
End Sub
Private Sub DoRunSelected()
IsTestRunning = True
Dim nTestsRun = 0
Dim nTestsFailed = 0
StopWatch = Diagnostics.Stopwatch.StartNew
Me.StatusText = String.Format("{0} Test run ({1}/{2}) ", DateTime.Now.ToString, nTestsRun, m_SelectedTests.Count)
Try
For Each lstItem In ListView1.Items
Dim tstItem = CType(lstItem, TestItem)
If tstItem.Selected Then
Me.ProgressBar1.Visibility = Windows.Visibility.Visible
tstItem.RunTest(Me) ' actually run the test
Me.ProgressBar1.Visibility = Windows.Visibility.Hidden
nTestsRun += 1
If tstItem.Status = TestItem.TstStatus.Failed Then
nTestsFailed += 1
End If
Me.StatusText = String.Format("{0} Test run {1}/{2} #Failed = {3}", DateTime.Now.ToString, nTestsRun, m_SelectedTests.Count, nTestsFailed)
If tstItem.Status = TestItem.TstStatus.Aborted Then
Exit For
End If
End If
Next
Catch ex As Exception
End Try
Me.StatusText = String.Format(" Done: {0:f2} secs", StopWatch.ElapsedMilliseconds / 1000)
IsTestRunning = False
End Sub
Private Sub ListBox1_KeyUp(ByVal sender As Object, ByVal args As System.Windows.Input.KeyEventArgs) Handles ListView1.KeyUp
If args.Key = Key.Space Then
Dim lb As System.Windows.Controls.ListBox = CType(sender, System.Windows.Controls.ListBox)
If lb.SelectedIndex >= 0 Then
Dim lbi = CType(lb.ItemContainerGenerator.ContainerFromIndex(lb.SelectedIndex), System.Windows.Controls.ListBoxItem)
If lbi IsNot Nothing Then
Dim tstItem = CType(lbi.Content, TestItem)
tstItem.Selected = Not tstItem.Selected
End If
End If
End If
End Sub
'see https://blogs.msdn.com/calvin\_hsia/archive/2007/11/29/6600915.aspx
Dim m_LastDir As System.ComponentModel.ListSortDirection = System.ComponentModel.ListSortDirection.Ascending
Dim m_LastHeaderClicked As System.Windows.Controls.GridViewColumnHeader = Nothing
Private Sub OnHeaderClicked(ByVal sender As Object, ByVal e As RoutedEventArgs)
If e.OriginalSource.GetType Is GetType(System.Windows.Controls.GridViewColumnHeader) Then
Dim direction = System.ComponentModel.ListSortDirection.Ascending
Dim gvHdr = CType(e.OriginalSource, System.Windows.Controls.GridViewColumnHeader)
If gvHdr IsNot Nothing AndAlso gvHdr.Column IsNot Nothing Then
Dim hdr As String
hdr = CStr(gvHdr.Column.Header)
If gvHdr Is m_LastHeaderClicked Then
If m_LastDir = System.ComponentModel.ListSortDirection.Ascending Then
direction = System.ComponentModel.ListSortDirection.Descending
End If
End If
Sort(hdr, direction)
m_LastHeaderClicked = gvHdr
m_LastDir = direction
End If
End If
End Sub
Private Sub Sort(ByVal sortby As String, ByVal dir As System.ComponentModel.ListSortDirection)
Me.ListView1.Items.SortDescriptions.Clear()
Dim sd = New System.ComponentModel.SortDescription(sortby, dir)
Me.ListView1.Items.SortDescriptions.Add(sd)
Me.ListView1.Items.Refresh()
End Sub
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) _
Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
</Window1.XAML.vb code to paste >
<MyTestHost.vb code to paste >
Imports System.Reflection
Imports System.Windows
Imports System.Collections.ObjectModel
Imports System.Windows.Controls
Imports System.ComponentModel
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Public Class MyTestHost
Private Shared m_TestMethods As ReadOnlyCollection(Of TestItem)
Shared Sub Main()
m_TestMethods = GetTestMethods()
If System.Environment.GetCommandLineArgs.Count > 1 Then ' arg 0 is the fullpath name of the app
Dim testname = System.Environment.GetCommandLineArgs(1)
Else
' show UI
Dim wpfApplicationWindow As System.Windows.Window = New Window1(m_TestMethods)
wpfApplicationWindow.ShowDialog()
End If
End Sub
Public Shared Function GetTestMethods() As ReadOnlyCollection(Of TestItem) ' can be called from other assemblies
Dim retval As New Collection(Of TestItem)
Dim MyAsm = Assembly.GetExecutingAssembly
Dim TestClasses = From typ In MyAsm.GetTypes Where typ.GetCustomAttributes(GetType(TestClassAttribute), True).Length > 0
For Each TestClassName In TestClasses
Debug.WriteLine("Test class " + TestClassName.Name)
Dim TestClassInstance = MyAsm.CreateInstance(TestClassName.FullName)
Dim TestMethods = From meth In TestClassInstance.GetType.GetMethods _
Where meth.GetCustomAttributes(GetType(TestMethodAttribute), True).Length > 0 _
AndAlso Not meth.GetCustomAttributes(GetType(IgnoreAttribute), True).Length > 0
Debug.WriteLine("Count=" + TestMethods.Count.ToString)
' you can define your own TestContext class
'Dim tstContext = New VBTest64TestContext
'Dim TestContext_Property As PropertyInfo = TestClassInstance.GetType.GetProperty("TestContext")
'If TestContext_Property IsNot Nothing Then
' TestContext_Property.SetValue(TestClassInstance, tstContext, BindingFlags.SetProperty, Nothing, Nothing, Nothing)
'End If
Dim TestInitialize_method As MethodInfo = TestClassInstance.GetType.GetMethod("TestInitialize")
Dim TestCleanup_method As MethodInfo = TestClassInstance.GetType.GetMethod("TestCleanup")
For Each meth In TestMethods ' In From dd In meths Where dd.Name.StartsWith("PepperQu")
Debug.WriteLine(meth.Name)
Dim TestDesc = ""
Dim TestOwner = ""
Dim TestPriority = ""
Dim Tmp = meth.GetCustomAttributes(GetType(Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute), True)
If Tmp.Length > 0 Then
TestDesc = CType(Tmp(0), Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute).Description
End If
Tmp = meth.GetCustomAttributes(GetType(OwnerAttribute), True)
If Tmp.Length > 0 Then
TestOwner = CType(Tmp(0), OwnerAttribute).Owner
End If
Tmp = meth.GetCustomAttributes(GetType(PriorityAttribute), True)
If Tmp.Length > 0 Then
TestPriority = CType(Tmp(0), PriorityAttribute).Priority.ToString
End If
retval.Add(New TestItem(meth.Name, TestClassName.FullName, TestDesc, _
TestOwner, TestPriority, meth, _
TestClassInstance, TestInitialize_method, TestCleanup_method))
Next
Next
Return New ReadOnlyCollection(Of TestItem)(retval)
End Function
End Class
Public Class TestItem
Implements INotifyPropertyChanged
Enum TstStatus
Idle
Pending
Running
Passed
Aborted
NotRun
Failed
End Enum
Private m_TestName As String
Private m_TestClass As String
Private m_Description As String
Private m_TestOwner As String
Private m_TestPriority As String
Private m_Selected As Boolean = True ' default to checkbox selected
Private m_TestStatus As TstStatus = TstStatus.Idle
Private m_TestInitialize_method As MethodInfo
Private m_TestCleanup_method As MethodInfo
Private m_TestMethodInfo As MethodInfo ' the actual test to run
Private m_TestClassInstance As Object
Private m_ElapsedTime As String
Private m_ErrorMessage As String
Private m_Stopwatch As Diagnostics.Stopwatch
Private Shared m_bgThread As System.Threading.Thread
Private Shared m_threadRunning As Boolean
Delegate Sub delThreadDone()
Private m_ThreadDoneEvent As System.Threading.ManualResetEvent
Sub New(ByVal TestName As String, ByVal TestClass As String, ByVal testDesc As String, _
ByVal TestOwner As String, ByVal TestPriority As String, _
ByVal meth As MethodInfo, ByVal TestClassInstance As Object, _
ByVal TestInitialize_method As MethodInfo, ByVal TestCleanup_method As MethodInfo)
m_TestName = TestName
m_TestClass = TestClass
m_Description = testDesc
m_TestOwner = TestOwner
m_TestPriority = TestPriority
m_TestMethodInfo = meth
m_TestInitialize_method = TestInitialize_method
m_TestCleanup_method = TestCleanup_method
m_TestClassInstance = TestClassInstance
End Sub
Shared Sub ShutDown()
If m_bgThread IsNot Nothing Then
m_bgThread.Abort()
Do While m_threadRunning
System.Windows.Forms.Application.DoEvents()
Loop
End If
End Sub
Sub BgThreadProc(ByVal disp As Object)
m_Stopwatch = Stopwatch.StartNew
Dim stat As TstStatus = TstStatus.Running
Status = TstStatus.Running
Dim deldone As New delThreadDone(AddressOf BgThreadDone)
Dim fDidRunCleanup = False
Debug.WriteLine(TestName)
Try
If m_TestInitialize_method IsNot Nothing Then
m_TestInitialize_method.Invoke(m_TestClassInstance, BindingFlags.InvokeMethod, Nothing, Nothing, Nothing)
End If
' run the test
m_TestMethodInfo.Invoke(m_TestClassInstance, Reflection.BindingFlags.InvokeMethod, Nothing, Nothing, Nothing)
If m_TestCleanup_method IsNot Nothing Then
m_TestCleanup_method.Invoke(m_TestClassInstance, BindingFlags.InvokeMethod, Nothing, Nothing, Nothing)
fDidRunCleanup = True
End If
stat = TstStatus.Passed
Catch ex As Exception 'When ex.GetType IsNot GetType(System.Threading.ThreadAbortException)
If ex.GetType Is GetType(System.Threading.ThreadAbortException) Then
If Not fDidRunCleanup Then
If m_TestCleanup_method IsNot Nothing Then
m_TestCleanup_method.Invoke(m_TestClassInstance, BindingFlags.InvokeMethod, Nothing, Nothing, Nothing)
fDidRunCleanup = True
End If
End If
Status = TstStatus.Aborted
ErrorMessage = "User aborted test run"
CType(disp, System.Windows.Threading.Dispatcher).Invoke(Threading.DispatcherPriority.Background, deldone)
Throw ex
End If
Debug.WriteLine(String.Format("Got exception {0} {1}", m_TestMethodInfo.Name, ex.InnerException.Message))
ErrorMessage = ex.InnerException.Message
stat = TstStatus.Failed
End Try
Me.Status = stat
mSecs = m_Stopwatch.ElapsedMilliseconds.ToString
m_Stopwatch.Stop()
Debug.WriteLine(TestName + " Done")
CType(disp, System.Windows.Threading.Dispatcher).Invoke(Threading.DispatcherPriority.Background, deldone)
End Sub
Sub BgThreadDone() ' runs on main thread
m_bgThread = Nothing
m_threadRunning = False
End Sub
Friend Sub RunTest(ByVal mWindow As Window1)
m_ThreadDoneEvent = New System.Threading.ManualResetEvent(False)
m_bgThread = New System.Threading.Thread(AddressOf BgThreadProc) ' cant' use BackgroundWorker because need STA
m_bgThread.Name = "MyTestHost runtests"
m_bgThread.SetApartmentState(System.Threading.ApartmentState.STA)
m_threadRunning = True
m_bgThread.Start(System.Windows.Threading.Dispatcher.CurrentDispatcher)
Do While m_threadRunning
If mWindow IsNot Nothing Then
Dim pbar As ProgressBar = mWindow.ProgressBar1
pbar.Value = DateTime.Now.Millisecond / 10
mWindow.Clock = (mWindow.StopWatch.ElapsedMilliseconds / 1000).ToString("f1")
End If
System.Windows.Forms.Application.DoEvents()
Loop
End Sub
Public Sub Reset()
mSecs = ""
ErrorMessage = ""
Status = TstStatus.Idle
End Sub
Public Property ErrorMessage() As String
Get
Return m_ErrorMessage
End Get
Set(ByVal value As String)
m_ErrorMessage = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("ErrorMessage"))
End Set
End Property
Public Property mSecs() As String
Get
Return m_ElapsedTime
End Get
Set(ByVal value As String)
m_ElapsedTime = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("mSecs"))
End Set
End Property
Public Property Status() As TstStatus
Get
Return m_TestStatus
End Get
Set(ByVal value As TstStatus)
If value <> m_TestStatus Then
m_TestStatus = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Status"))
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("StatusColor"))
End If
End Set
End Property
Public ReadOnly Property StatusColor() As String
Get
Select Case m_TestStatus
Case TstStatus.Failed
Return "Red"
Case TstStatus.Idle
Return "LightBlue"
Case TstStatus.Pending
Return "Purple"
Case TstStatus.Aborted
Return "Red"
Case TstStatus.Passed
Return "Green"
Case TstStatus.NotRun
Return "Black"
Case Else
Return "Blue"
End Select
End Get
End Property
Public ReadOnly Property TestName() As String
Get
Return m_TestName
End Get
End Property
Public ReadOnly Property TestClass() As String
Get
Return m_TestClass
End Get
End Property
Public ReadOnly Property Description() As String
Get
Return m_Description
End Get
End Property
Public ReadOnly Property Owner() As String
Get
Return m_TestOwner
End Get
End Property
Public ReadOnly Property Pri() As String
Get
Return m_TestPriority
End Get
End Property
Public Property Selected() As Boolean
Get
Return m_Selected
End Get
Set(ByVal value As Boolean)
m_Selected = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Selected"))
End Set
End Property
Public Overrides Function ToString() As String
Return String.Format("{0,-20} {1}", m_TestName.PadRight(20), m_TestClass)
End Function
Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
End Class
</MyTestHost.vb code to paste >
End of blog entry
Comments
Anonymous
March 27, 2008
PingBack from http://music.fashion-info-news.info/create-your-own-test-host-using-xaml-to-run-your-unit-tests/Anonymous
March 27, 2008
PingBack from http://music.government-news.info/create-your-own-test-host-using-xaml-to-run-your-unit-tests/Anonymous
March 28, 2008
I'd suggest that this functionality be added to VS's support for unit testing so that this functionality is supported and the test cases can be maintained over 5+ years of use.Anonymous
April 03, 2008
My prior post ( Create your own Test Host using XAML to run your unit tests ) shows how to create a formAnonymous
April 11, 2008
Writing programs using .Net is very productive. One reason is because much of memory management is “managed”Anonymous
April 19, 2008
PingBack from http://joselin.freetvnewssite.com/canyoudisplayanarrowinexcel.htmlAnonymous
May 09, 2008
PingBack from http://triston.freemusicoutletdesign.info/run16bitprogramonvista64.htmlAnonymous
July 28, 2008
What does it mean to make code more maintainable? Certainly obfuscated code is hard to understand, by