8

I've been looking at some articles about local functions, and the one sentence states:

Local functions are defined within a method and aren't available outside of it

So given the below code example is there any way to unit test the square method?

int SumAndSquare(int x, int y)
{
    var sum = x + y;
    return square(sum);

    int square(int z)
    {
        return z * z;
    }
}
urig
  • 16,016
  • 26
  • 115
  • 184
Adam T
  • 776
  • 7
  • 18
  • 3
    By unit testing `SumAndSquare`. That's the unit (or not in this case, as it's private, but it would be if it was public). – Jon Hanna Mar 10 '17 at 10:04
  • 3
    In the same way you unit test private methods: you don't. You unit test the public part of your class. – xanatos Mar 10 '17 at 10:05
  • You can only test the outcome of the SumAndSquare-Method. Not the local function. – bslein Mar 10 '17 at 10:05
  • @xanatos it's possible to test private methods using the PrivateObject Class, see [this](http://stackoverflow.com/questions/9122708/unit-testing-private-methods-in-c-sharp) question. I'm interested in knowing if a solution exists for testing local funcations – Adam T Mar 10 '17 at 10:07
  • 2
    @AdamT But I support the accepted response of [Keith Nicholas](http://stackoverflow.com/a/9122724/613130): *Yes, don't Test private methods.... The idea of a unit test is to test the unit by its public 'API'.* . I'm not saying that it isn't possible to execute private methods... I use reflection even to heat the milk in the morning :-) – xanatos Mar 10 '17 at 10:09
  • 1
    Check the duplicate even if it is about F#. F# supports nested functions from day 1. They are extremely useful but not a replacement for private methods. For example, if a nested function is used only by its parent, why would you need to test it separately? If it's so complicated that it needs testing, you are probably doing it wrong – Panagiotis Kanavos Mar 10 '17 at 10:15
  • 1
    I don't see that the F# question is a valid duplicate. – Ian Ringrose Apr 03 '17 at 19:01

1 Answers1

9

In general you can't in a maintainable way for non-trivial local functions (reason explained in a comment to this response). A local function that uses variables of the method where it is defined (so a non-trivial one, ones that don't use local variables could be private methods) has a special parameter containing these variables. You can't easily recreate this parameter → you can't call it.

It can be easily seen in TryRoslyn (how much I love TryRoslyn! I use it very often )

int Foo()
{
    int b = 5;
    return valueofBplusX(5);

    int valueofBplusX(int x)
    {
        return b + x;
    }
}

is translated in something like:

[CompilerGenerated]
[StructLayout(LayoutKind.Auto)]
private struct <>c__DisplayClass0_0
{
    public int b;
}

private int Foo()
{
    C.<>c__DisplayClass0_0 <>c__DisplayClass0_ = default(C.<>c__DisplayClass0_0);
    <>c__DisplayClass0_.b = 5;
    return C.<Foo>g__valueofBplusX0_0(5, ref <>c__DisplayClass0_);
}

[CompilerGenerated]
internal static int <Foo>g__valueofBplusX0_0(int x, ref C.<>c__DisplayClass0_0 ptr)
{
    return ptr.b + x;
}

You see the <>c__DisplayClass0_0 that contains the b local variable, and the <Foo>g__valueofBplusX0_0 that receives as the second argument a ref C.<>c__DisplayClass0_0 ptr?

On top of this, I'll add a quote of Keith Nicholas: Yes, don't Test private methods.... The idea of a unit test is to test the unit by its public 'API'.

Community
  • 1
  • 1
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • I'm not saying you should, but you still _can_ do this, by constructing an instance of the display class using reflection as well. – caesay Mar 10 '17 at 10:23
  • @caesay It isn't maintainable (I was waiting for this question )... The name of the local variables of a function aren't part of its "external interface"... They can be changed/refactored at the whim of a programmer, and this will break your unit testing (because your unit test will break on filling the `<>c__DisplayClass0_0`). – xanatos Mar 10 '17 at 10:25
  • TryRoslyn gives a great insight into whats actually happening, I can see how hard it would be to maintain unit tests on local methods. – Adam T Mar 10 '17 at 10:31