Can I call nested functions for unit testing?

In F #, I want to do unit function testing with several levels of nested functions. I also want to be able to test nested functions separately, but I don’t know how I can call them. When debugging, each of these nested functions is called as a type of function object, but I don’t know if I can access them at compile time.

I do not want to change the nesting scheme that I use, because it makes the most functional sense, so that they are nested in this way, because there is a de facto "inheritance" of some function parameters at each nested level.

Is something like this possible? If not, what is the general procedure for unit testing nested functions? Are they checked individually with additional parameters, and then inserted into their nested positions after the words are not checked again?

A very small example:

let range ab = let lower = ceil a |> int let upper = floor b |> int if lower > upper then Seq.empty else seq{ for i in lower..upper -> i} 

How can I verify that lower or upper are working fine without changing the nesting of the code?

+4
source share
1 answer

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) 
+7
source

Source: https://habr.com/ru/post/1415456/


All Articles