What does non - testable mean in this code example? - unit-testing

I need to analyze a code after playing a code and see if I have full coverage. Some part of the report is shown below:
game->errorCode = ERROR_NO_MEMORY;
#pragma RVS justification( "COV_STATEMENTS", "not testable");
}
else {
/* Initialize platform */
game->errorCode = platformInit(game);
if (game->errorCode == ERROR_NONE) {
/* If platform was correctly initialized, start the game */
startGame(game);
} else {
#pragma RVS justification( "COV_MCDC", "1:game->errorCode == ERROR_NONE", "not testable");
#pragma RVS justification( "COV_DECISIONS", "not testable");
}
What does it mean when they say "not testable"? Is it a part of code that cannot be covered? And if so why?

The term non-testable is used since, from the point of view of correctness testing, if one cannot decide whether or not the output is correct or must expend some extraordinary amount of time to do so, there is nothing to be gained by performing the test.

In this particular case "not testable" is used to tell a coverage analysis tool (RVS) that a certain piece of code shall not be taken into consideration in the coverage report.
From looking at the code I would say that this code definitely looks testable - it requires that the test has control over what platformInit returns (whether it makes more sense to test this in unit-testing or in integration testing would be a different question). Consequently, the statement about the respective branches being "not testable" is wrong - but the intent here is not to give a true statement about testability, the intent is that although that branch is not covered by the respective tests, it shall not negatively influence the results in the coverage report.

Related

Does 100% code coverage mean that the code is correct?

If you have 100% test coverage and all tests pass does that mean that the code is guaranteed to be correct and writing more tests is pointless?
It's only correct as far as the logic of your testing is correct.
I'll give the most stupid example possible...
If I for example have a class (Java):
public class Example {
public int timesTwo(int x){
return x*2;
}
}
with the following test (which you can see it being illogical and useless)
public class ExampleTest {
#Test
public void timesTwo() {
new Example().timesTwo(5);
assertTrue(true);
}
}
Most coverage tools will say that this class has been tested 100%!
So no, coverage is a good indicator of what needs to be tested; but the test logic itself isn't assured.
If you have 100% test coverage and all tests pass does that mean that the code is guaranteed to be correct and writing more tests is pointless?
No. Counter-example: For a division-function a testcase with 0 as divisor can be missing (example taken from here: https://stackoverflow.com/a/555824/3905529 ). The tests verify that the function is working with the inputs used in the unit-tests. But there may be edge-cases where the code throws exceptions and there is maybe no unit-test which asserts exactly this, even with a coverage of 100%.
Another problem I have often seen is that for a condition the if-block will be handled and tested but else-block is missing and there is also no test that verifies that the else-case will be handled in the function. This is else-part may be missing completely. So the test is green, but the function has semantical flaws due to missing code. But the coverage can still be 100% because there are only tests for the existing code, but not for the missing parts of it.
Beside this there may be other issues, see:
https://sqa.stackexchange.com/a/36940

If TDD is for units, how can a test accidentally pass first (as a mistake)?

I have read a study about TDD and one of the common issues (survey between developers) stated that they are not really letting the test fail first. The authors then state:
If a new test does not fail, programmers receive an indication that
the production code was not working as they thought it was and a code
revision might be necessary. Another problem that might occur is that
programmers cannot be sure about what made the test pass; nothing
ensures the new code was actually responsible for it. The test
implementation might have been wrong since the beginning.
I wonder, how can a TDD test ever pass first (because of the production code, like they mention), if it on a unit level? I mean, if all is mocked (stubbed..), it should be always isolated and thus never cannot really pass first.
Let's assume you have two classes Calculator and Formatter.
Calculator calculates some value based on input and Formatter converts the value to string for displaying.
You already have some tests in your FormatterTest:
test_value_is_formatted_as_number
test_empty_is_formatted_as_NA
Now you implement new feature Show zero values as N/A.
Following TDD you will add a test to Formatter test_zero_is_formatted_as_NA that checks this first and you expect it to fail:
def test_zero_is_formatted_as_NA(self):
assert formatter.format(0) == 'N/A'
But it happens that it passes and the reason is Formatter already does this but Calculator returns floating zero which has limited precision.
def format(value):
if value == 0 or value is None:
return 'N/A'
return format_as_string(value)
So the test passes but if you write another test it would fail:
def test_very_small_number_is_treated_as_zero_and_formatted_as_NA(self):
assert formatter.format(0.00000001) == 'N/A'
Usually, situations that you describe easily happen when something is already implemented but another part of the system (using this implemented part) is somehow limiting it, for example by stronger preconditions. Then if you do not know well the code, you might encounter such a surprise.
Consider this example:
public string ShowScoreEvaluation(byte points)
{
switch(points)
case 3:
return "You are good!";
case 2:
return "Not bad!";
case 1:
return "Quite bad";
case 0:
return "You suck!"
}
//caller code
if (Points>0)
ShowScoreEvaluation(points)
In the code above, the calling code does not expect to call the method when Points=0. Maybe during the implementation of that method, the programmer just put something there (as a joke or a placeholder) even for the case when points=0.
And now imagine, that you joins the project and get a new request "When player has 0 points, show an encouraging message blabla".
You write a unit test with Points=0 and expecting a string with length>0...and it did not fail, although you would expect it.

Should I use assert to verify a third party function?

I use some third party function which based on the filter returns specified number of objects:
//void GetObjects(std::vector<T>&, Filter, int /*objectsNumber*/)
GetObjects(vec, filter, 1);
if(vec.empty())
{
throw ObjectNotFound();
}
assert(vec.size() == 1);
Should I use assert like above ? Is it a typical assert scenario ?
How to handle errors in your program depends on you, and on your program nature.
In a production environment, you usually try not to assert because then it means your application dies. In other cases, the process that executes your program would realize your program died and then restart it.
If it's just for learning/training, asserting with a proper message is a good way to find your problem easily and fast.
Bottom line - it's really up to you. There's no right or wrong here.
If you do want to assert, usually you do it only when some very basic invariant/condition is not met, when your program just cannot know how to proceed from this point.
Well, assert() is a macro that allows the checking code to be disabled for production code, so ensuring that the foreign function complies to the interface contract, it's a good custom to use assert to ensure the function specification are met.
Anyway, using mock instances and some Unit testing framework will give you better results, as it allows you to ensure the interface contract with finer exposure to foreign mistakes. I recommend you both, and happy to see those ideas circulating over these environments :)

Should it be "Arrange-Assert-Act-Assert"?

Regarding the classic test pattern of Arrange-Act-Assert, I frequently find myself adding a counter-assertion that precedes Act. This way I know that the passing assertion is really passing as the result of the action.
I think of it as analogous to the red in red-green-refactor, where only if I've seen the red bar in the course of my testing do I know that the green bar means I've written code that makes a difference. If I write a passing test, then any code will satisfy it; similarly, with respect to Arrange-Assert-Act-Assert, if my first assertion fails, I know that any Act would have passed the final Assert - so that it wasn't actually verifying anything about the Act.
Do your tests follow this pattern? Why or why not?
Update Clarification: the initial assertion is essentially the opposite of the final assertion. It's not an assertion that Arrange worked; it's an assertion that Act hasn't yet worked.
This is not the most common thing to do, but still common enough to have its own name. This technique is called Guard Assertion. You can find a detailed description of it on page 490 in the excellent book xUnit Test Patterns by Gerard Meszaros (highly recommended).
Normally, I don't use this pattern myself, since I find it more correct to write a specific test that validates whatever precondition I feel the need to ensure. Such a test should always fail if the precondition fails, and this means that I don't need it embedded in all the other tests. This gives a better isolation of concerns, since one test case only verifies one thing.
There may be many preconditions that need to be satisfied for a given test case, so you may need more than one Guard Assertion. Instead of repeating those in all tests, having one (and one only) test for each precondition keeps your test code more mantainable, since you will have less repetition that way.
It could also be specified as Arrange-Assume-Act-Assert.
There is a technical handle for this in NUnit, as in the example here:
http://nunit.org/index.php?p=theory&r=2.5.7
Here's an example.
public void testEncompass() throws Exception {
Range range = new Range(0, 5);
assertFalse(range.includes(7));
range.encompass(7);
assertTrue(range.includes(7));
}
It could be that I wrote Range.includes() to simply return true. I didn't, but I can imagine that I might have. Or I could have written it wrong in any number of other ways. I would hope and expect that with TDD I actually got it right - that includes() just works - but maybe I didn't. So the first assertion is a sanity check, to ensure that the second assertion is really meaningful.
Read by itself, assertTrue(range.includes(7)); is saying: "assert that the modified range includes 7". Read in the context of the first assertion, it's saying: "assert that invoking encompass() causes it to include 7. And since encompass is the unit we're testing, I think that's of some (small) value.
I'm accepting my own answer; a lot of the others misconstrued my question to be about testing the setup. I think this is slightly different.
An Arrange-Assert-Act-Assert test can always be refactored into two tests:
1. Arrange-Assert
and
2. Arrange-Act-Assert
The first test will only assert on that which was set up in the Arrange phase, and the second test will only assert for that which happened in the Act phase.
This has the benefit of giving more precise feedback on whether it's the Arrange or the Act phase that failed, while in the original Arrange-Assert-Act-Assert these are conflated and you would have to dig deeper and examine exactly what assertion failed and why it failed in order to know if it was the Arrange or Act that failed.
It also satisfies the intention of unit testing better, as you are separating your test into smaller independent units.
I am now doing this. A-A-A-A of a different kind
Arrange - setup
Act - what is being tested
Assemble - what is optionally needed to perform the assert
Assert - the actual assertions
Example of an update test:
Arrange:
New object as NewObject
Set properties of NewObject
Save the NewObject
Read the object as ReadObject
Act:
Change the ReadObject
Save the ReadObject
Assemble:
Read the object as ReadUpdated
Assert:
Compare ReadUpdated with ReadObject properties
The reason is so that the ACT does not contain the reading of the ReadUpdated is because it is not part of the act. The act is only changing and saving. So really, ARRANGE ReadUpdated for assertion, I am calling ASSEMBLE for assertion. This is to prevent confusing the ARRANGE section
ASSERT should only contain assertions. That leaves ASSEMBLE between ACT and ASSERT which sets up the assert.
Lastly, if you are failing in the Arrange, your tests are not correct because you should have other tests to prevent/find these trivial bugs. Because for the scenario i present, there should already be other tests which test READ and CREATE. If you create a "Guard Assertion", you may be breaking DRY and creating maintenance.
I don't use that pattern, because I think doing something like:
Arrange
Assert-Not
Act
Assert
May be pointless, because supposedly you know your Arrange part works correctly, which means that whatever is in the Arrange part must be tested aswell or be simple enough to not need tests.
Using your answer's example:
public void testEncompass() throws Exception {
Range range = new Range(0, 5);
assertFalse(range.includes(7)); // <-- Pointless and against DRY if there
// are unit tests for Range(int, int)
range.encompass(7);
assertTrue(range.includes(7));
}
Tossing in a "sanity check" assertion to verify state before you perform the action you're testing is an old technique. I usually write them as test scaffolding to prove to myself that the test does what I expect, and remove them later to avoid cluttering tests with test scaffolding. Sometimes, leaving the scaffolding in helps the test serve as narrative.
I've already read about this technique - possibly from you btw - but I do not use it; mostly because I'm used to the triple A form for my unit tests.
Now, I'm getting curious, and have some questions: how do you write your test, do you cause this assertion to fail, following a red-green-red-green-refactor cycle, or do you add it afterwards ?
Do you fail sometimes, perhaps after you refactor the code ? What does this tell you ? Perhaps you could share an example where it helped. Thanks.
I have done this before when investigating a test that failed.
After considerable head scratching, I determined that the cause was the methods called during "Arrange" were not working correctly. The test failure was misleading. I added a Assert after the arrange. This made the test fail in a place which highlighted the actual problem.
I think there is also a code smell here if the Arrange part of the test is too long and complicated.
In general, I like "Arrange, Act, Assert" very much and use it as my personal standard. The one thing it fails to remind me to do, however, is to dis-arrange what I have arranged when the assertions are done. In most cases, this doesn't cause much annoyance, as most things auto-magically go away via garbage collection, etc. If you have established connections to external resources, however, you will probably want to close those connections when you're done with your assertions or you many have a server or expensive resource out there somewhere holding on to connections or vital resources that it should be able to give away to someone else. This is particularly important if you're one of those developers who does not use TearDown or TestFixtureTearDown to clean up after one or more tests. Of course, "Arrange, Act, Assert" is not responsible for my failure to close what I open; I only mention this "gotcha" because I have not yet found a good "A-word" synonym for "dispose" to recommend! Any suggestions?
Have a look at Wikipedia's entry on Design by Contract. The Arrange-Act-Assert holy trinity is an attempt to encode some of the same concepts and is about proving program correctness. From the article:
The notion of a contract extends down to the method/procedure level; the
contract for each method will normally contain the following pieces of
information:
Acceptable and unacceptable input values or types, and their meanings
Return values or types, and their meanings
Error and exception condition values or types that can occur, and their meanings
Side effects
Preconditions
Postconditions
Invariants
(more rarely) Performance guarantees, e.g. for time or space used
There is a tradeoff between the amount of effort spent on setting this up and the value it adds. A-A-A is a useful reminder for the minimum steps required but shouldn't discourage anyone from creating additional steps.
Depends on your testing environment/language, but usually if something in the Arrange part fails, an exception is thrown and the test fails displaying it instead of starting the Act part. So no, I usually don't use a second Assert part.
Also, in the case that your Arrange part is quite complex and doesn't always throw an exception, you might perhaps consider wrapping it inside some method and writing an own test for it, so you can be sure it won't fail (without throwing an exception).
If you really want to test everything in the example, try more tests... like:
public void testIncludes7() throws Exception {
Range range = new Range(0, 5);
assertFalse(range.includes(7));
}
public void testIncludes5() throws Exception {
Range range = new Range(0, 5);
assertTrue(range.includes(5));
}
public void testIncludes0() throws Exception {
Range range = new Range(0, 5);
assertTrue(range.includes(0));
}
public void testEncompassInc7() throws Exception {
Range range = new Range(0, 5);
range.encompass(7);
assertTrue(range.includes(7));
}
public void testEncompassInc5() throws Exception {
Range range = new Range(0, 5);
range.encompass(7);
assertTrue(range.includes(5));
}
public void testEncompassInc0() throws Exception {
Range range = new Range(0, 5);
range.encompass(7);
assertTrue(range.includes(0));
}
Because otherwise you are missing so many possibilities for error... eg after encompass, the range only inlcudes 7, etc...
There are also tests for length of range (to ensure it didn't also encompass a random value), and another set of tests entirely for trying to encompass 5 in the range... what would we expect - an exception in encompass, or the range to be unaltered?
Anyway, the point is if there are any assumptions in the act that you want to test, put them in their own test, yes?
I use:
1. Setup
2. Act
3. Assert
4. Teardown
Because a clean setup is very important.

Test Cases VS ASSERTION statement

In my most C++ project I heavily used ASSERTION statement as following:
int doWonderfulThings(const int* fantasticData)
{
ASSERT(fantasticData);
if(!fantasticData)
return -1;
// ,,,
return WOW_VALUE;
}
But TDD community seems like to enjoy doing something like this:
int doMoreWonderfulThings(const int* fantasticData)
{
if(!fantasticData)
return ERROR_VALUE;
// ...
return AHA_VALUE;
}
TEST(TDD_Enjoy)
{
ASSERT_EQ(ERROR_VALUE, doMoreWonderfulThings(0L));
ASSERT_EQ(AHA_VALUE, doMoreWonderfulThings("Foo"));
}
Just with my experiences first approaches let me remove so many subtle bugs.
But TDD approaches are very smart idea to handle legacy codes.
"Google" - they compare "FIRST METHOD" to "Walk the shore with life-vest, swim ocean without any safe guard".
Which one is better?
Which one makes software robust?
In my (limited) experience the first option is quite a bit safer. In a test-case you only test predefined input and compare the outcome, this works well as long as every possible edge-case has been checked. The first option just checks every input and thus tests the 'live' values, it filters out bugs real quickly, however it comes with a performance penalty.
In Code Complete Steve McConnell learns us the first method can be used successfully to filter out bugs in a debug build. In release build you can filter-out all assertions (for instance with a compiler flag) to get the extra performance.
In my opinion the best way is to use both methods:
Method 1 to catch illegal values
int doWonderfulThings(const int* fantasticData)
{
ASSERT(fantasticData);
ASSERTNOTEQUAL(0, fantasticData)
return WOW_VALUE / fantasticData;
}
and method 2 to test edge-cases of an algorithm.
int doMoreWonderfulThings(const int fantasticNumber)
{
int count = 100;
for(int i = 0; i < fantasticNumber; ++i) {
count += 10 * fantasticNumber;
}
return count;
}
TEST(TDD_Enjoy)
{
// Test lower edge
ASSERT_EQ(0, doMoreWonderfulThings(-1));
ASSERT_EQ(0, doMoreWonderfulThings(0));
ASSERT_EQ(110, doMoreWonderfulThings(1));
//Test some random values
ASSERT_EQ(350, doMoreWonderfulThings(5));
ASSERT_EQ(2350, doMoreWonderfulThings(15));
ASSERT_EQ(225100, doMoreWonderfulThings(150));
}
Both mechanisms have value. Any decent test framework will catch the standard assert() anyway, so a test run that causes the assert to fail will result in a failed test.
I typically have a series of asserts at the start of each c++ method with a comment '// preconditions'; it's just a sanity check on the state I expect the object to have when the method is called. These dovetail nicely into any TDD framework because they not only work at runtime when you're testing functionality but they also work at test time.
There is no reason why your test package cannot catch asserts such as the one in doMoreWonderfulThings. This can be done either by having your ASSERT handler support a callback mechanism, or your test asserts contain a try/catch block.
I don't know which particlar TDD subcommunity you're refering to but the TDD patterns I've come across either use Assert.AreEqual() for positive results or otherwise use an ExpectedException mechanism (e.g., attributes in .NET) to declare the error that should be observed.
In C++, I prefer method 2 when using most testing frameworks. It usually makes for easier to understand failure reports. This is invaluable when a test months to years after the test was written.
My reason is that most C++ testing frameworks will print out the file and line number of where the assert occurred without any kind of stack trace information. So most of the time you will get the reporting line number inside of the function or method and not inside of the test case.
Even if the assert is caught and re-asserted from the caller the reporting line will be with the catch statement and may not be anywhere close to the test case line which called the method or function that asserted. This can be really annoying when the function that asserted may have been used on multiple times in the test case.
There are exceptions though. For example, Google's test framework has a scoped trace statement which will print as part of the trace if an exception occurs. So you can wrap a call to generalized test function with the trace scope and easily tell, within a line or two, which line in the exact test case failed.