|
|
|
|
|
by yakubin
1558 days ago
|
|
I see completely different problem. Just because there are branches in your code, doesn't mean there are branches in its inputs. And just because there are branches in the inputs, doesn't mean they are reflected in the code. So you may have 100% test coverage, but be testing branches which aren't going to be taken, at the same time completely missing the branches that are in the inputs, which you'll fail to handle. Example: fn abs(x: i32) -> u32 {
x as u32
}
fn test_abs() {
assert_eq!(5, abs(5));
}
Boom, 100% test coverage! But the tests are actually very low quality. There is a bug when x is negative. That's why property-based testing is nice. It uncovers branches in the inputs (although the task of generating a representative set for the inputs is sometimes non-trivial).After discovering the bug, one may even write a branchless implementation of this function for performance without updating the test, and it will still be 100% coverage. But the arithmetic has "logical branches" which do not look like ifs, instead they generate qualitatively different results for different inputs. |
|
In school I wrote parsers. At work I have done it but it's rare.
In fact if you write commercial code you'll often find that the code that you rely on that is like that weirdly gets concentrated in open source libraries which you will be testing only indirectly.
Certainly when writing commercial code I find that the majority of bugs lurk in the interstitial spaces between subsystems I am integrating or in misunderstandings about how the overall system or subparts of it are supposed to behave.
And property tests are not much help there and unit tests are often a hindrance (because theyre as likely to bake in wrong assumptions).
TDD is some help with this but only if A) it's paired with BDD to exorcize specification bugs and B) done with integration tests that exercise all parts of the system together.