I agree with Daniels comment: if an external function works correctly, you do not need to check any internal functions. Internal functions are actually implementation details that should not be relevant (especially in functional code, where the output does not depend on anything other than input). In C #, you also don't check if the for
loop or while
inside your method works.
If both the inner and outer functions are too complex, it might be better to write the inner function as a separate function.
However, you can, of course, ruin the compiled assembly using reflection and call the internal function. Internal functions are compiled as classes with a constructor that accepts a closure (captured values ββof an external function) and an Invoke
method that accepts the actual parameters.
The following trivial example works, although I have not tested it for something more realistic:
open NUnit.Framework // Function with 'inner' that captures the argument 'a' and takes additional 'x' let outer ab = let inner x = x + a + 1 (inner a) * (inner b) // Unit tests that use reflection in a hacky way to test 'inner' [<TestFixture>] module Tests = open System open System.Reflection // Runs the specified compiled function - assumes that 'name' of inner functions // is unique in the current assembly (!) and that you can correctly guess what // are the variables captured by the closure (!) let run name closure args = // Lots of unchecked assumptions all the way through... let typ = Assembly.GetExecutingAssembly().GetTypes() |> Seq.find (fun typ -> let at = typ.Name.IndexOf('@') (at > 0) && (typ.Name.Substring(0, at) = name) ) let flags = BindingFlags.Instance ||| BindingFlags.NonPublic let ctor = typ.GetConstructors(flags) |> Seq.head let f = ctor.Invoke(closure) let invoke = f.GetType().GetMethod("Invoke") invoke.Invoke(f, args) /// Test that 'inner 10' returns '14' if inside outer where 'a = 3' [<Test>] let test () = Assert.AreEqual(run "inner" [| box 3 |] [| box 10 |], 14)
source share