Unit testing cyclomatically complicated but otherwise trivial calculations - unit-testing

Let's say I have a calculator class who primary function is to do the following (this code is simplified to make the discussion easier, please don't comment on the style of it)
double pilingCarpetArea = (hardstandingsRequireRemediation = true) ? hardStandingPerTurbineDimensionA * hardStandingPerTurbineDimensionB * numberOfHardstandings * proportionOfHardstandingsRequiringGroundRemediationWorks : 0;
double trackCostMultipler;
if (trackConstructionType = TrackConstructionType.Easy) trackCostMultipler = 0.8
else if (trackConstructionType = TrackConstructionType.Normal) trackCostMultipler = 1
else if (trackConstructionType = TrackConstructionType.Hard) trackCostMultipler = 1.3
else throw new OutOfRangeException("Unknown TrackConstructionType: " + trackConstructionType.ToString());
double PilingCostPerArea = TrackCostPerMeter / referenceTrackWidth * trackCostMultipler;
There are at least 7 routes through this class I should probably test, the combination of trackCostMultiplier and hardstandingsRequireRemediation (6 combinations) and the exception condition. I might also want to add some for divide by zero and overflow and suchlike if I was feeling keen.
So far so good, I can test this number of combinations easily and stylishly. And actually I might trust that multiplication and addition are unlikely to go wrong, and so just have 3 tests for trackCostMultipler and 2 for hardstandingsRequireRemediation, instead of testing all possible combinations.
However, this is a simple case, and the logic in our apps is unfortunately cyclomatically much more complicated than this, so the number of tests could grow huge.
There are some ways to tackle this complexity
Extract the trackCostMultipler calculation to a method in the same class
This is a good thing to do, but it doesn't help me test it unless I make this method public, which is a form of "Test Logic In Production". I often do this in the name of pragmatism, but I would like to avoid if I can.
Defer the trackCostMultipler calculation to a different class
This seems like a good thing to do if the calculation is sufficiently complex, and I can test this new class easily. However I have just made the testing of the original class more complicated, as I will now want to pass in a ITrackCostMultipler "Test Double" of some sort, check that it gets called with the right parameters, and check that its return value is used correctly. When a class has, say, ten sub calculators, its unit / integration test becomes very large and difficult to understand.
I use both (1) and (2), and they give me confidence and they make debugging a lot quicker. However there are definitely downsides, such as Test Logic in Production and Obscure Tests.
I am wondering what others experiences of testing cyclomatically complicated code are? Is there a way of doing this without the downsides? I realise that Test Specific Subclasses can work around (1), but this seems like a legacy technique to me. It is also possible to manipulate the inputs so that various parts of the calculation return 0 (for addition or subtraction) or 1 (for multiplication or division) to make testing easier, but this only gets me so far.
Thanks
Cedd

Continuing the discussion from the comments to the OP, if you have referentially transparent functions, you can first test each small part by itself, and then combine them and test that the combination is correct.
Since constituent functions are referentially transparent, they are logically interchangeable with their return values. Now the only remaining step would be to prove that the overall function correctly composes the individual functions.
The is a great fit for property-based testing.
As an example, assume that you have two parts of a complex calculation:
module MyCalculations =
let complexPart1 x y = x + y // Imagine it's more complex
let complexPart2 x y = x - y // Imagine it's more complex
Both of these functions are deterministic, so assuming that you really want to test a facade function that composes these two functions, you can define this property:
open FsCheck.Xunit
open Swensen.Unquote
open MyCalculations
[<Property>]
let facadeReturnsCorrectResult (x : int) (y : int) =
let actual = facade x y
let expected = (x, y) ||> complexPart1 |> complexPart2 x
expected =! actual
Like other property-based testing frameworks, FsCheck will throw lots of randomly generated values at facadeReturnsCorrectResult (100 times, by default).
Given that both complexPart1 and complexPart2 are deterministic, but you don't know what x and y are, the only way to pass the test is to implement the function correctly:
let facade x y =
let intermediateResult = complexPart1 x y
complexPart2 x intermediateResult

You need another abstraction level to make your methods simpler, so it will be easier to test them:
doStuff(trackConstructionType, referenceTrackWidth){
...
trackCostMultipler = countTrackCostMultipler(trackConstructionType)
countPilingCostPerArea = countPilingCostPerArea(referenceTrackWidth, trackCostMultipler)
...
}
countTrackCostMultipler(trackConstructionType){
double trackCostMultipler;
if (trackConstructionType = TrackConstructionType.Easy) trackCostMultipler = 0.8
else if (trackConstructionType = TrackConstructionType.Normal) trackCostMultipler = 1
else if (trackConstructionType = TrackConstructionType.Hard) trackCostMultipler = 1.3
else throw new OutOfRangeException("Unknown TrackConstructionType: " + trackConstructionType.ToString());
return trackCostMultipler;
}
countPilingCostPerArea(referenceTrackWidth, trackCostMultipler){
return TrackCostPerMeter / referenceTrackWidth * trackCostMultipler;
}
Sorry for the code, I don't know the language, does not really matter...
If you don't want to make these methods public, then you have to move them to a separate class, and make them public there. The class name could be TrackCostMultiplerAlgorithm or ..Logic or ..Counter, or something like that. So you will be able to inject the algorithm into the higher abstraction level code if you'll have more different algorithms. Everything depends on the actual code.
Ohh and don't worry about the method and class lengths, if you really need a new method or class, because the code is too complex, then create one! Does not matter that it will be short. It will be always ease understanding as well, because you can write into the method name what it does. The code block inside the method only tells us how it does...

Related

Number of test-cases for a boolean function

I'm confused about the number of test cases used for a boolean function. Say I'm writing a function to check whether the sale price of something is over $60 dollars.
function checkSalePrice(price) {
return (price > 60)
}
In my Advance Placement course, they ask the minimum # of test include boundary values. So in this case, the an example set of tests are [30, 60, 90]. This course I'm taking says to only test two values, lower and higher, eg (30, 90)
Which is correct? (I know this is pondering the depth of a cup of water, but I'd like to get a few more samples as I'm new to programming)
Kent Beck wrote
I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence (I suspect this level of confidence is high compared to industry standards, but that could just be hubris). If I don't typically make a kind of mistake (like setting the wrong variables in a constructor), I don't test for it. I do tend to make sense of test errors, so I'm extra careful when I have logic with complicated conditionals. When coding on a team, I modify my strategy to carefully test code that we, collectively, tend to get wrong.
Me? I make fence post errors. So I would absolutely want to be sure that my test suite would catch the following incorrect implementation of checkSalePrice
function checkSalePrice(price) {
return (price >= 60)
}
If I were writing checkSalePrice using test-driven-development, then I would want to calibrate my tests by ensuring that they fail before I make them pass. Since in my programming environment a trivial boolean function returns false, my flow would look like
assert checkSalePrice(61)
This would fail, because the method by default returns false. Then I would implement
function checkSalePrice(price) {
return true
}
Now my first check passes, so I know what this boundary case is correctly covered. I would then add a new check
assert ! checkSalePrice(60)
which would fail. Providing the corrected implementation would pass the check, and now I can confidently refactor the method as necessary.
Adding a third check here for an arbitrary value isn't going to provide additional safety when changing the code, nor is it going to make the life of the next maintainer any easier, so I would settle for two cases here.
Note that the heuristic I'm using is not related to the complexity of the returned value, but the complexity of the method
Complexity of the predicate might include covering various problems reading the input. For instance, if we were passing a collection, what cases do we want to make sure are covered? J. B. Rainsberger suggested the following mnemonic
zero
one
many
lots
oops
Bruce Dawson points out that there are only 4 billion floats, so maybe you should [test them all].
Do note, though, that those extra 4 billion minus two checks aren't adding a lot of design value, so we've probably crossed from TDD into a different realm.
You stumbled into on of the big problems with testing in general - how many tests are good enough?!
There are basically three ways to look at this:
black box testing: you do not care about the internals of your MuT (method under test). You only focus on the contract of the method. In your case: should return return true when price > 60. When you think about this for while, you would find tests 30 and 90 ... and maybe 60 as well. It is always good practice to test corner cases. So the answer would be: 3
white box testing: you do coverage measurements of your tests - and you strive for example to hit all paths at least once. In this case, you could go with 30 and 90 - which would be resulting in 100% coverage: So the answer here: 2
randomized testing, as guided by QuickCheck. This approach is very much different: you don't specify test cases at all. Instead you step back and identify rules that should hold true about your MuT. And then the framework creates random input and invokes your MuT using that - trying to find examples where the aforementioned rules break.
In your case, such a rule could be that: when checkSalePrice(a) and checkSalePrice(b) then checkSalePrice(a+b). This approach feels unusual first, but as soon as start exploring its possibilities, you can find very interesting things in it. Especially when you understand that your code can provide the required "creator" functions to the framework. That allows you to use this approach to even test much more complicated, "object oriented" stuff. It is just great to watch the framework find a flaw - and to then realize that the framework will even find the "minimum" example data required to break a rule that you specified.

Clojure, Attempting to call unbound fn

I tried to create factorial function in Clojure using recursion
(defn fac[x] (if (= x 1) 1 (* x (fac (- x 1)))))
Now, when I try to call the function
(fac 5)
I get the exception
java.lang.IllegalStateException: Attempting to call unbound fn: #'sandbox11355/fac
Does that mean it isn't possible to use recursion when defining functions with defn keyword?
Also, how would I embrace this functional syntax most efficiently, as I'm used to imperative/OOP way of thinking? It feels just awkward to type everything in the reverse order. With procedural paradigm, the continuum of thoughts maps directly to new line of code which mutates the value. With functional syntax, for each step to manipulate the current value, I have to wrap new function around the expression, and it's hard to keep track of parens and scopes. Should I learn to think the procedural model in reverse order to fluently code in functional style?
I understand the benefits of no mutable state and pure functions (less bugs), but it's hard to believe it's worth of losing the ease of writing procedural code. For now, all this seems over-hyped unorganized mess, but maybe it starts making sense.
Some info on your concern about functional and procedural programming follows. It's not particularly original, but maybe it will get you started on how to think about this new stuff.
Functional programming is not procedural programming in reverse. It's a higher level of abstraction, and most everything we interact with can be seen as an abstraction; otherwise, we would never get anything useful done because we'd be so concerned with the minutiae of every little thing we deal with. Likewise, all code, in any language, eventually becomes a series of instructions to the CPU, and these instructions are the epitome of "imperative" or "procedural." The question becomes, "How much control do I need over the extremely low details in order to solve my problem?"
One way to add some numbers together, being pretty explicit (just pseudocode, hopefully the intent is clear):
int nums[10] = {0,1,2,3,4,5,6,7,8,9};
int i = 0;
int acc = 0;
start_loop:
if (i >= 10) goto done_loop;
int num_address = (nums + i);
int num_value = *num_address;
acc = acc + num_value;
i = i + 1;
goto start_loop;
done_loop:
return acc;
It is tedious, but not as tedious as assembly code. To abstract out some of the details of looping, C/java/etc provide a control structure called a for loop:
int nums[10] = {0,1,2,3,4,5,6,7,8,9};
int acc = 0;
for (int i = 0; i < 10; i++)
acc += nums[i];
return acc;
This seems perfectly normal, of course, when you write imperative code on a regular basis. You think iteratively, and about the details of how to access the array at each offset from its base. However, this can also be thought of as tedious. Why should I care about the details of how to access each member of the array? A further abstraction that any functional languages provides is called reduce. Think of it as a tool provided in a similar way that for is provided to C/java/etc programmers. It looks strange, much in the same way the syntax of for would look to assembly programmers seeing it for the first time:
(reduce + (range 10))
So all we're doing here is abstracting out details of the loop to the point that we really don't think much about the loop that's actually occurring. We also abstract out the details of creating an explicit range of numbers, and just say "give me the integers from 0 (inclusive) to 10 (exclusive)". It's just abstracting out details. The result is generally an ability to focus more on the problem at hand.
For adding numbers, or thinking higher level, a functional way of programming generally allows us to be more productive, with less code, while we let the various levels of compilers handle the messy details for us. If the problem is very low level, however, then we may desire constructs in the language that are a better fit for our problem. The key is always using the right tool for the right job.
Of course, it's not a perfect world, and often in clojure we are forced to write low level details dealing with bits and bytes, synchronizing concurrent code, looping, and so on. But generally, being declarative and stating what you want to do, rather than being more explicit about how to do it, has many benefits.
Do the 4clojure problems, give it a month or two to start really making sense, and allow your mind to make the shift from mutating variables to evaluating expressions. There's a very high probability that you will enjoy it very much, and the worst that can happen is that you can broaden your horizons. Good luck and have fun!

Many boolean based code paths

I have an issue with one of my classes. It has many bools in it, and the functions in said class have to handle many different paths based on these values. All of these paths make the code very bloated and hard to read. I was wondering if there was a design pattern or some principle rule I could follow to made the code run the same but easier to understand and read.
To be more specific, the class is called Actor. It is for a video game that I'm helping with. The Actor class manages the hands of a humanoid in the game. The hands work together in some actions and operate independently in others. So there are a massive amount of Boolean variables to check what each of them are doing. This is all in the update loop (somewhere) and I think this functionality should be moved or simplified somehow. I think there are about 20 different bool values, with more on the way.
Also, I know my post is game dev related, but I feel the question is a general one.
So are there any ways to fix / help this?
Edit:
I'll explain more. Say you have 4 bools: isAttacking, isDefending, isCasting, isDrugged.
So you have to check each hand if it is busy and handle the the paths like:
Player tries to attack with a two handed weapon ->
if not isDefending and not isCasting then isAttacking = true, if isDrugged then attack with value 1 else 5.
It just gets complicated quickly and when you factor in more bools it gets very complex.
So what I'm saying is: I'm lazy is there a better way to do this?
With your example with 4 bool, you have 16 (2**4) possible behaviors:
so you may build an array of behaviors and then dispatch it, something like:
void UpdateTick()
{
const std::uint32_t behaviorIndex =
(isAttacking << 0)
| (isDefending << 1)
| (isCasting << 2)
| (isDrugged << 3);
const std::function<void(void)> behaviors[16] = {
f_NoDrugNoCastNoDefNoAtt,
f_NoDrugNoCastNoDefAtt,
f_NoDrugNoCastDefNoAtt,
f_NoDrugNoCastDefAtt,
f_NoDrugCastNoDefNoAtt,
f_NoDrugCastNoDefAtt,
f_NoDrugCastDefNoAtt,
f_NoDrugCastDefAtt,
f_DrugNoCastNoDefNoAtt,
f_DrugNoCastNoDefAtt,
f_DrugNoCastDefNoAtt,
f_DrugNoCastDefAtt,
f_DrugCastNoDefNoAtt,
f_DrugCastNoDefAtt,
f_DrugCastDefNoAtt,
f_DrugCastDefAtt,
}
behaviors[behaviorIndex]();
}

Test of lot of math operations in a class

Is there a way of testing functions inside a class in an easy way for correct results? I mean, I have been looking at google test unit testing, but seems more to find fails in the work classes and functions, more than in the expected result.
For example, from math theory one could know which is the square root of all numbers, now you want to check a sqrt function, seeking for floating point precision errors, and then you also want to check lot of functions that use floats and look for any precision error, is there a way to make this easy and fast ?
I can think of 2 direct solutions
1)
one of the easiest ways to test for accuracy of mathematical functions is similar to what is used as definition work for limits in calculus. taking the value to be tested, and then also using a value that is "close" on both sides. I have heard of analogies drawn between limit analysis and unit testing, but keep in mind that if your looking for speed this will not be your best options. and that this will only work on continues operations, and that this analogy is for definition work only
so what you would do is have a "limitDomain" variable defined per function (this is because some operations are more accurate then others for reasoning look up taylor approximation of [function]), and then use that as you limiter. then test: low, high, and then the value itself, and then take the avg of all three within a given margin of error,
float testMathOpX(float _input){
float low = 0.0f;
float high = 0.0f;
low = _input - limitDomainOpX;
high = _input + limitDomainOpX;
low = OpX(low);
_input = OpX(_input);
high = OpX(high);
// doing 3 separate averages with division by 2 mains the worst decimal you will have is a trailing 5, or in some cases a trailing 25
low = (low + _input)/2
high = (_input + high)/2;
_input = (low + high)/2
return _input;
}
2)
the other method that I can think of is more of a table of values approach being that you take the input, and then check to see where on the domain of the operation it lies, and if it lies within certain values then you use value replacement. The thing to realize is that you need to have a lot of work ahead of time to get these table of values, and then it becomes just domain testing of the value your taking in in the form of:
if( (_input > valLow) && (_input < valHigh)){
... replace the value with an empirically found value
}
the problem with this is that you need o find those empirically found values.
Do you have requirements on the precision or do you want to find the precision?
If it is the former, then it is not hard to create test cases using any test framework.
y = myfunc(x);
if (y > expected_y + allowed_error || y < expected_y - allowed_error) {
// Test failed
...
}
Edit:
There are two routes to finding the precision, through testing and through algorithm analysis.
Testing should be straightforward: Compare the output with the correct values (which you have to obtain in some way).
Algortithm analysis is when you calculate the expected size of the error by calculating the error of the algorithm and the error caused by lack of precision in floating point arithmetic.

Help Unit Testing cascading calculations

I have a class that is used as part of a financial application. The class is bound to a UI form and accepts a handful of values that are then used to calculate financial data. The calculated values are presented as properties on the object. Several of these calculations use other calculations.
For example, CalculationA may return PropertyA + PropertyB. CalculationB returns PropertyC - CalculationA. (This is an extreme over-simplification).
I am trying to write some unit tests to make sure that these calculations are performed correctly and wondering what approach I should be taking.
My first approach was to manually recalculate the expected result in the test method. For example, when testing CalculationB, I populate the test object then set the expected result equal to PropertyC - PropertyA + PropertyB. But since the real object has 25 properties involved, this is quite cumbersome.
On option I thought of is to simply create the test object, populate it with values then write a test that verifies CalculationA equals PropertyA + PropertyB and another test that verifies CalculationB equals PropertyC - CalculationB. The latter assumes that CalculationB is correct, but does that really matter for the purpose of the unit test?
What guidance/suggestions can you make for setting up my tests so they are accurate, reliable and maintainable? What is the best way to ensure that the calculations are correct and that I didn't accidentally set CalculationB = PropertyB - CalculationA, for instance.
Your case sounds equivalent to a spreadsheet, and a spreadsheet is just unusual syntax for code of the form:
f1(f2(a, f3(b)), c);
Where f1-3 are the calculations, and a-c the input properties. The 'chaining' is the fact that the outputs of some functions are used as inputs to others.
This kind of functional calculation code is where unit testing really shines. Testing the assembly as a whole means that a change to the specification of f3 would change the test cases for f2 and f1 in some complicated but meaningless way. This could well result in someone cutting and pasting the calculation result back into the test as the expected result. Which kind of makes the whole exercise a little pointless.
So if a minimal set of test cases is something like:
f1(7, -2) => 23
f2(1, 2) => 7
f3(4) => 5
then you can implement each of those test cases by:
set all properties to fixed large numbers
set the input properties to the input for this case
check the output property
Because point one is shared between all tests, the effort to produce test cases for each calculation is proportional only to the complexity of that specific calculation, not the total number of properties.