2

How do I create unit tests for out parameters of a private function?

My service layer:

private int LoadProduct(string productId, out IProduct product)
{
    product = this.Load(productId);

    return ErrorCodes.Success;
}

Test case:

[Test]
public void LoadProductTest()
{
    var offerService = new OfferProcessor();
    var privateOfferService = new PrivateObject(offerService);

    IProduct myProduct = null;

    var result = (int)privateOfferService.Invoke("LoadProduct", 
                       new object[] {"AnId", myProduct });

    Assert.That(result, Is.EqualTo(ErrorCodes.Success));
    Assert.That(myProduct, Is.NotNull());
}

The above test case does not compile. How do I pass Invoke an out parameter and then access it after the call?

rboarman
  • 8,248
  • 8
  • 57
  • 87
  • 4
    In general, I try to always test the private methods through the public interface. Shouldn't, strictly speaking, need to unit test a private member directly. – James Michael Hare Aug 07 '12 at 19:12
  • Does this answer your question? http://weblogs.asp.net/peterblum/archive/2009/12/10/reflection-on-a-method-with-an-out-parameter.aspx – Tim S. Aug 07 '12 at 19:12
  • http://stackoverflow.com/questions/2438065/c-sharp-reflection-how-can-i-invoke-a-method-with-an-out-parameter – Colin D Aug 07 '12 at 19:12
  • @rboarman....Test methods are intended to test external facing functionality. Functionality that can be called from outside of a class. A private method is satisfactorily tested by the class. To test LoadProduct(), you would want to call the public method(s) that access it. – MikeTWebb Aug 07 '12 at 19:13
  • I asked a similar question http://stackoverflow.com/questions/11565560/what-are-the-good-practice-to-test-inject-private-field-in-c-sharp – HatSoft Aug 07 '12 at 19:14
  • A corrolary to what the others are saying: if your private methods "feel" complex enough that you think they should be tested on their own, you should consider extracting them into a separate class that's a collaborator of this one. (As per the Single Responsibility Principle.) – millimoose Aug 07 '12 at 19:14
  • 3
    I believe it's considered good practice to return the actual object, and *not* use error codes for return values. If there is an error, throw an exception. And if you return the actual business object, you won't have this issue. – Bob Horn Aug 07 '12 at 19:15
  • possible duplicate of [Unit testing private methods in C#](http://stackoverflow.com/questions/9122708/unit-testing-private-methods-in-c-sharp) – Peter Ritchie Aug 07 '12 at 19:16
  • And what about your code doesn't compile? In VS you can right-click on a method and choose Create Unit Tests... VS will do the plumbing for you. – Bob Horn Aug 07 '12 at 19:16
  • [This](http://stackoverflow.com/a/3253105/650012) answer to an older SO question describes how you can use the `InternalsVisibleTo]` attribute. That is, provided you are able/willing to rebuild your service layer and make `LoadProduct`method `internal`. – Anders Gustafsson Aug 07 '12 at 19:20
  • @PeterRitchie The example you reference does not deal with out parameters – rboarman Aug 07 '12 at 19:20
  • @rboarman your title says "without parameters" not "with out parameters"... – Peter Ritchie Aug 07 '12 at 19:22

3 Answers3

5

try saving the object array that you pass the invoke call.

object[] args = new object[] { "AnId", myProduct };
var result = (int)privateOfferService.Invoke("LoadProduct", args);
Assert.That(args[1], Is.NotNull());

https://stackoverflow.com/a/2438069/1311351

Community
  • 1
  • 1
Colin D
  • 5,641
  • 1
  • 23
  • 35
3

You can, if you really, really need to test this method, mark it internal and specify the InternalsVisibleTo attribute for the class to your test namespace. But yeah, just test the public interface.

Jasper
  • 2,610
  • 14
  • 19
  • 2
    You shouldn't change your implementation to allow for testing. – Bob Horn Aug 07 '12 at 19:19
  • Why not? You change it for readability, Why not for testability? – seldary Aug 08 '12 at 10:27
  • Because now other code has access to it. There was a reason for making it private in the first place. Changing it for readability is not the same issue as changing it for testability. – Bob Horn Aug 08 '12 at 15:08
  • Perhaps the private methods should be refactored to become public methods of a different, specialized object? http://blogs.msdn.com/b/jaybaz_ms/archive/2004/06/11/153978.aspx – Jakub Kaleta Aug 08 '12 at 22:09
3

I believe it's considered good practice to return the actual object, and not use error codes for return values. If there is an error, throw an exception. And if you return the actual business object, you won't have this issue.

Since you don't say what about your code doesn't compile, I'm assuming your test method can't access the private method. VS will allow you to test private methods if you do this (right-click in the method and choose Create Unit Tests...):

enter image description here

Bob Horn
  • 33,387
  • 34
  • 113
  • 219