0

As per this answer to Unit testing private methods in C# I am using a PrivateObject to unit test private methods. This generally works really well and is quite easy to use, however it doesn't appear to work if the method is Shared or Static.

I don't really want to make the method public (otherwise I wouldn't even be bothering with PrivateObjects but I'm failing to see another way.

Example vb methods in class being tested:

    Private Sub SampleInstanceMethod(arg as Object)
        'Do something
    End Sub
    Private Shared Sub SampleSharedMethod(arg as Object)
        'Do something
    End Sub

Unit test code

    Dim fooBarPO = New PrivateObject(GetType(FooBar))
    fooBarPO.Invoke("SampleInstanceMethod", {arg1}) ' Works
    fooBarPO.Invoke("SampleSharedMethod", {arg1}) ' Doesn't work

Interested in answers in either C# or VB

theduck
  • 2,526
  • 13
  • 15
  • 22
  • 1
    In general, it's not a good idea to unit test private methods. Recommend to prefer to test them through the public interface of whatever class you're testing. Unit testing private methods makes your tests dependent on implementation details and thus can hinder refactoring. – Craig Nov 11 '19 at 13:51
  • @Craig that's a very broad statement and if you check the linked question there are many people arguing both ways about whether private methods require testing. So I don't think its quite so clear cut. In this particular case, while it could be detected from the public interface, deducing the cause could be troublesome, while the test I'm implementing would immediately highlight exactly where the problem is if this method was incorrectly refactored. – Notts90 supports Monica Nov 11 '19 at 14:07
  • 2
    The point isn't that they don't require testing, the point is that the preferred way to test them is through the public interface. That's "preferred," not "the only way" or "the one true way." It seems like you've given this some thought and still concluded that private method testing is still what's best for you. – Craig Nov 11 '19 at 14:18
  • If you have a private method that's difficult to test through a public API, this points to a design problem. The solution is to refactor it into smaller units that can be individually tested, **not** to find a convoluted way to test private methods. – Daniel Mann Nov 11 '19 at 15:02
  • @DanielMann I don't believe the method in the accepted answer to be convoluted at all. I see this as being advantages over testing the API as if there is an issue with this method in the future it will be very quick and easy to diagnose. The reason a private method is being used is to break the code into smaller units that can be unit tested. – Notts90 supports Monica Nov 11 '19 at 15:19

1 Answers1

2

You could use PrivateType and InvokeStatic for this:

    Dim foo = New PrivateType(GetType(TestClass))
    foo.InvokeStatic("SampleSharedMethod", {arg1})

If you want to pass parameters ByRef - for instance if the method under test looked something like this:

    Private Shared Sub SampleSharedMethod(ByRef arg As String)
       arg += "abc"
    End Sub

You can use this overload of InvokeStatic to get the results back:

    Dim foo = New PrivateType(GetType(TestClass))
    Dim params() As Object = {"123"}
    foo.InvokeStatic("SampleSharedMethod", params)

    Dim updatedValue = params(0) ' This would be 123abc in this example
theduck
  • 2,526
  • 13
  • 15
  • 22