Caves Travel Diving Graphics Mizar Texts Cuisine Lemkov Contact Map RSS Polski
Trybiks' Dive Texts Testing PrivateObject, WithEvents, and generics YAC Software
  Back

List

Charsets

Charts

DBExpress

Delphi

HTML

Intraweb

MSTest

PHP

Programming

R

Rhino Mocks

Software

Testing

UI Testing

VB.NET

VCL

WPF

PrivateObject, WithEvents, and generics
In the previous texts on PrivateObject (here, here, and here) all examples dealt with simple fields and non-generic types. Moreover, the examples in the last text were a bit contrived - at least I have never found the need to access private members of base classes... I think. However, the solution discussed there will help in one particular example - accessing protected fields marked with WithEvents in base generic classes.

Let's say that you have code similar to this:
  Public Class A
  
    Public Event E()
  
  End Class
  
  Public Class X
  
    Protected WithEvents B As A
  
    Public Sub OnE1() Handles B.E
    End Sub
  
  End Class
  
  Public Class Y1
    Inherits X
  
  End Class
  
  Public Class Y2
    Inherits X
  
    Public Sub OnE2() Handles B.E
    End Sub
  
  End Class
No problem accessing B, through PrivateObject, when testing either Y1 or Y2:
  <TestMethod()>
  Public Sub TestY()
    Dim a As New A
    Dim y1 As New Y1
    Dim y2 As New Y2
    Dim y1Accessor As New PrivateObject(y1)
    Dim y2Accessor As New PrivateObject(y2)
  
    y1Accessor.SetFieldOrProperty("B", a)
    y2Accessor.SetFieldOrProperty("B", a)
  
    . . .
  End Sub
However, I often have a situation where X is actually a generic type, and the WithEvents field is of the type specified in the generic definition (used, for instance, in command definitions that reference different types of view models):
  Public Class X(Of T As A)
  
    Protected WithEvents B As T
  
    Public Sub OnE1() Handles B.E
    End Sub
  
  End Class
  
  Public Class Y1
    Inherits X(Of A)
  
  End Class
  
  Public Class Y2
    Inherits X(Of A)
  
    Public Sub OnE2() Handles B.E
    End Sub
  
  End Class
If you try to test this using standard code with PrivateObject:
  <TestMethod()>
  Public Sub TestY()
    Dim a As New A
    Dim y1 As New Y1
    Dim y2 As New Y2
    Dim y1Accessor As New PrivateObject(y1)
    Dim y2Accessor As New PrivateObject(y2)
  
    y1Accessor.SetFieldOrProperty("B", a)
    y2Accessor.SetFieldOrProperty("B", a)
  
    . . .
  End Sub
you'll get the following exception on the second call to SetFieldOrProperty:

System.Reflection.AmbiguousMatchException: Ambiguous match found.

As discussed previously, VB.NET generates hidden properties that are used to manage VB.NET's Handles directives. Here, we actually have an overridable property B declared in class X, and that property is overridden in class Y2. But, in the first case, PrivateObject can access it without problems, whereas in the second case, we get the exception...

Actually, at first I thought the problem is entirely due to some special handling of WithEvents / Handles directives in VB.NET, but the example can be simplified as follows:
  Public Class X(Of T As {Class})
  
    Protected Overridable Property X As T
  
  End Class
  
  Public Class Y
    Inherits X(Of Object)
  
    Protected Overrides Property X As Object
  
  End Class
  
  <TestMethod()>
  Public Sub TestMethodY1()
    Dim y As New Y
    Dim yAccessor As New PrivateObject(y)
  
    yAccessor.SetProperty("X", 1)
  End Sub
And this causes an error too (but if you drop the generic definition, and use Object instead of T in B's declaration, everything works as expected).

Actually, I think it's some sort of a bug in PrivateObject's implementation... (If you look at the generated code in dotPeek, for instance, it looks the same in both cases.)

Fortunately, there is a way to get around this - just use PrivateObject with the constructor that takes a PrivateType parameter:
  <TestMethod()>
  Public Sub TestMethodY1()
    Dim y As New Y
    Dim yAccessor As New PrivateObject(y, New PrivateType(GetType(X(Of Object))))
  
    yAccessor.SetProperty("X", 1)
  End Sub
Happy testing!

Top

Comments
#1
mhollis wrote on 2012-12-20 23:33:56
Great advice about using the PrivateObject's constructor's second parameter to specify the type when dealing with a class that inherits from a generic base class. I had this EXACT problem and your solution worked perfectly.

Top

Add a comment (fields with an asterisk are required)
Name / nick *
Mail (will remain hidden) *
Your website
Comment (no tags) *
Enter the text displayed below *
 

Top

Tags

Testing

VB.NET


Related pages

AssertWasCalled and Methods Called Multiple Times

AssertWas[Not]Called and Object Properties

Rhino Mocks's AssertWasNotCalled

Visual Studio - moving coded UI tests to a new / different project results in null reference exceptions

PrivateObject and Out/ByRef parameters

Accessing private members of base classes

CA1800:DoNoCastUnnecessarily

PrivateObject and WithEvents

The creator of this fault did not specify a Reason.

Accessing private and protected members - PrivateObject and PrivateType

VS - Test Run Error - "COM object that has been separated from its underlying RCW cannot be used"

Saving / restoring window placements in .NET

Get the TreeViewItem for an Item in a WPF TreeView

Output in MSTest Tests (VS 2010)

Automated WPF tests and "Invalid URI: Invalid port specified."

Checking Property Change Notifications

Checking "Dangling" Event Handlers in Delphi Forms

Rhino Mocks's AssertWasCalled in VB.NET

First steps with Rhino Mocks (in VB.NET)

Meaningful identifiers

Public fields vs. properties

VS Pending Tests

Automated GUI Testing

Automated GUI Testing in VMs

Automated Testing of Window Forms

Detecting Memory Leaks with DUnit