i am doing one Android app.My client is asking me to include assertions in the android code.I have googled across and found that Commonsware says that assertions should be avoided in android code.But i need a strong reason why using assertions is avoided?
Please let me know if i should use assertions or not.And if so what are the rules or suggestions using assertions in android.
But i need a strong reason why using assertions is avoided?
An assertion is intentionally introducing an unhandled, uncatchable error (AssertionError, specifically).
Assertions do no work in Android by default. You have to specifically enable them. This means that whatever logic you are trying to validate via assertions will not be employed on production devices.
Hence, I agree with this assessment:
Step zero: Refactor comments into assertions
Step one: Refactor assertions out of the code into unit tests
Step three: Escalate the remaining assertions into program exceptions
So you are certainly welcome to validate inputs, confirm outputs, etc. Just do not use assert. Instead, handle the condition in some other fashion. If nothing else, throw a RuntimeException like an IllegalArgumentException, so that your top-level unhandled-exception logic can get control.
A trivial search of the Internet will turn up many articles regarding the choice of assertions versus exceptions, such as:
https://softwareengineering.stackexchange.com/questions/137158/is-it-better-to-use-assert-or-illegalargumentexception-for-required-method-param
https://stackoverflow.com/a/1276318/866172
What would be the point of such an Assert ?
On a production code Asserts are not going to do much good, they will only detect why what you considered as an invariant is not as you expected, but it won't prevent your app from crashing.
Furthermore, the Assert Class is part of junit.framework.Assert, it is here to be used in an unit test.
So it is a way better practice to establish unit tests that will tests these invariants, that way you can act when a future development breaks them.
Related
When should I use assert in code, instead of writing a junit test. Are they the same?
The question I believe is not specific to java or any particular language
The java built-in asserts require that the JVM is invoked with a special flag. That reduces their usefulness quite a bit.
You should also understand the differences between testing your product in your test environment versus doing validations within the production environment.
Meaning: you always strive to test all public methods of your classes with unit tests (where you use unit test asserts). You always strive to make your application robust so that it doesn't crash at your customers, but at least gives clear error messages and creates logs for you to debug issues.
But those things are really different aspects of development.
Regarding the comment: JUnit simply provides those many different versions of assert statements for one reason only: expressiveness. Meaning: they help you to write test code that is easy to understand, such as:
assertThat(actualValue, is(expectedValue))
where is() is a matcher provided by the hamcrest library. If you intend to learn about unit testing: simply remember that you only "need" assertThat() together with hamcrest matchers.
We have a project with > 80% test coverage but the quality of the code is still a problem. Some changes will bring in new bugs ever with test cases to cover the logic.
What's the best rules to write the JUnit test cases?
A tip first: when developing new code, start doing it in a unit test
Do not start with border cases, null tests
Make stable tests, which will not easily be broken with source changes
For scenarios with business data, sequences, make help functions
Catching regression errors, weakness in the code usage is the main goal
New code often merits to be redesigned, a rewrite when some additional functionality crystallizes. A unit test should not be a burdon, and be entirely rewritten too
Some effort can better go into the tested code.
100% coverage also implies that much effort went into test code and its maintenance.
However if a unit test of a source is cumbersome, refactor the original code by splitting responsibilities. This can be done ugly by using inheritance for separating different aspects.
Rely on findbugs/coverity, selenium and such too.
You said "Some changes will bring in new bugs ever with test cases to cover the logic".
My question is what kind of bugs are introduced? Are these functional bugs say missing a functionality or a functionality not working as expected even though the code and Unit test both are there.
Then I would say you need to do some requirement mapping. Junits are not only helpful to cover the "written code", but you should also look at the requirements/scenarios and there should be atleast one unit-test for each scenario. Every time there is a change in functionality, make sure you update/add the Junit first (so it will start failing), then update/add/remove code. So the failed Junit now start passing.
Java assert statements are selectively enabled/disabled, based on config flags (eg, -ea). I read online that with JUnit assertions (eg, Assert.assertTrue), you don't need to worry about managing the assertion-config yourself. What exactly does this mean? Either:
1) JUnit assertions (mixed together with Prod code) are never disabled. They behave just like Validate statements, and always get run.
or
2) The JUnit test framework automatically enables all JUnit assertions when running JUnit tests. Whenever the application/code is run outside of JUnit, the JUnit assert methods do nothing at all.
or
3) JUnit assertions are always enabled/disabled by default, but there is a custom config/flag that can be used to disable/enable them
Which of the above is true?
--
Edit: Changed the wording a little bit to clear up any ambiguity.
This question seems to have opened up a can of worms with regards to coding-guidelines on when to use/not to use asserts. I'll post here the answer to my immediate question regarding whether JUnit Assert statements get disabled. Further down, you will find a discussion on the philosophical aspects of using assertions.
Summary: JUnit assert statements are never disabled, even when running in production with the disable-assertions flag.
Experiment: Created a small main function which throws an error in the very first line. The error was implemented in various different ways. I then ran the application from the command-line like so: mvn clean package; java $JAVA_OPTS -cp ....
Induced error by throwing IllegalArgument exception. Application failed with IllegalArgument exception.
Induced error by adding assert false and ran with assertions enabled (-ea). Application failed.
Induced error by adding assert false and ran with assertions disabled (-da). Application succeeded.
Induced error by adding Assert.assertTrue(false); and ran with assertions enabled (-ea). Application failed with AssertionError.
Induced error by adding Assert.assertTrue(false); and ran with assertions disabled (-da). Application failed with AssertionError.
Did a quick google search to see if there's any way to disable JUnit.Asserts. Didn't find anything. If anyone knows of a way to do so, please let me know, because I believe it's an important distinction.
Conclusion: assert keywords can be enabled/disabled using the -ea commandline flag. JUnit.Asserts cannot be enabled/disabled. If you want to add assertions to your production code, then this becomes a very important distinction. If you want the ability to disable them, use the assert keyword. If you want something that you know will always be enabled, then consider JUnit.Assert, or some other similar framework that throws AssertionErrors.
Regarding the philosophy behind assert usage:
It's good to add assertions of some form to your production code. See: https://docs.oracle.com/javase/8/docs/technotes/guides/language/assert.html#usage
Putting Assertions Into Your Code. There are many situations where it is good to use assertions, including:
Internal Invariants
Control-Flow Invariants
Preconditions, Postconditions, and Class Invariants
JUnit Asserts cannot be treated as a universal replacement for java assert keywords. The latter gives you the power to disable them, and the former doesn't. Hence, there is a design choice to be made in choosing which of the 2 to use.
Exceptions and Assertions serve very different purposes and should not be used interchangeably. The following discussion clarifies this further: When to use an assertion and when to use an exception
Related StackOverflow discussions:
assert vs. JUnit Assertions
I think you're confused between JUnit assertions and Java's built in assertions.
JUnit assertions are methods that throw an AssertionError exception and should only be used in your test code. JUnit code should not be used in production, only when running your JUnit tests during/between builds. The method names are named like assertEquals( expected, actual) and assertNull(Object) etc. You can't disable these assertions since they are method calls. Also your test code would be pretty useless if you could disable all the JUnit assert methodcalls.
Java's built in assertion is a boolean expression preceded by the assert keyword. If the expression returns false, then it too throws an AssertionError. This kind of assertion can be disabled in production to help speed up your code or turned on to help track down bugs. You can read more about the built in Java assert in the Java Programming Guide
My question is from the perspective of language design.
Why is assert treated differently i.e. it raises a error and not an exception, it is not enabled by default etc..
It does seem elegant(very subjective opinion), easy to read(again subjective) for doing validations & also there are tools(IDE) which can live-evaluate it and provide warnings based on assertions.
I'd say that the reason is that defaults for Java are meant for production code (the "release" version of software) - if users need to build your code they will use provided defaults and if you are developer and want to have better reporting you can always make some additional effort.
Usually you don't want to ship assertions with a release version. Why? You can always design your code to perform some not disturbing background error handling and throwing AssertionError in users face is not always the way to go.
Most of the time I see them used as additional code testing - when you run regression tests and code coverage is high no assertion error suggest that there are no (obvious to spot) errors in your code. If some happens, you can deduce from stack trace what went wrong and why. On the other hand clients shouldn't be bothered with seeing descriptive error information.
So how should you actually use them? In my experience you should design code to not use assertions to perform error handling. If you want exception to be thrown somewhere throw it explicitly yourself. Once code can handle itself, you can add assertions to check pre- and postconditions as well as invariants - so basically used them to check algorithm correctness instead of data correctness. It has value for developers rather than users. Once you have enough confidence in your solution, you can disable assertions, your program still works fine and your users don't have to run program with additional runtime overhead.
Asserts are tools for the developer.
The core reason it's not enabled by default is that assertions via assert are not meant to provide run-time validation/protection for production code.
assert is a tool for use in development process and during testing that should not impact performance during actual running in production environment.
Imagine a very heavy weight assertions that are critical to check when building out a new feature or a change against a entire range of allowable inputs, but once built and properly tested, don't need to run until code changes again.
It raises an error, because the severity of an assertion violation is high enough to do so.
An example for an Exception is something like ArrayIndexOutOfBounds. This might be reasonable in some cases and you might even expect (and handle) such a case.
But an assertion violation is (like out of memory e.g.) nothing you would ever expect or you would like to deal with. It's an error and there is no excuse.
Assertions are not enabled by default, because they should be always fullfilled. You enable them to test for that, but then you "know" (as far as you can know) that they are not violated. So you don't need to check the conditions (which might be performance intensive) every time in production code.
The good thing about assertions in Java is, that the code actually performing the checks is never executed, when assertions are not enabled.
For example:
if (!doComplexChecks()) throw new AssertionError("Damn!");
might take a lot of time and you want to verify this when unit testing or debugging, but in production you just don't want that.
But this code
assert doComplexChecks();
is only executed, when assertions are enabled, so it saves you a lot of time in production code.
My line coverage for unit tests measured by Cobertura is suffering, because I have assert statements which are not covered in tests. Should I be testing assertions, and is there any way to get Cobertura to ignore them so they do not affect my test coverage?
The line coverage of your Java assert statements should be simply covered by running your test suite with assertions enabled, i.e., giving -ea as argument to the jvm.
If you do this, you'll see that cobertura easily reports 100% line coverage if the rest of your lines are covered as well.
Nevertheless, the assert lines will still be colored red, suggesting insufficient coverage.
This is because your assertions are usually always true, so you never hit the false branch.
Thus, branch coverage in Cobertura is messed up by using assert, since assert lines will have 50% branch coverage, rendering the overall branch coverage percentage hard to interpret (or useless).
Clover has a nice feature to ignore assert when computing coverage. I haven't seen this feature in any open source Java coverage tool.
If you use assertions in a design-by-contract style, there is no need to add tests that make your Java assert statements fail. As a matter of fact,
for many assertions (e.g., invariants, post-conditions) you cannot even create objects that would make them fail, so it is impossible to write such tests.
What you can do, though, is use the invariants/postconditions to derive test cases exercising their boundaries -- see Robert Binder's invariant boundaries pattern. But this won't make your assertions fail.
Only if you have a very tricky pre-condition for a given method, you may want to consider writing a test aimed at making the pre-condition fail. But then re-thinking your pre-condition may be a better idea.
There's a feature request (1959691) already logged for Cobertura to add the ability to ignore assert lines; feel free to watch it in case they implement and add a comment to the page if you think it's a good idea. It's a shame none of the opensource coverage tools support this yet, as I definitely think assert statements are a good idea, but testing them usually isn't practical/possible.
Code coverage is a tool which allow you to improve your testing, it is not a some kind of proof for the validity of your tests. You get the value from it by aiming to having 100% code coverage, looking at what is not covered, and reflecting on how to improve your tests.
Finding that there are uncovered assert statements is just an example where you should call: "ok, no need to cover this". A similar examples for this is with tracing macros and debug code which adds hidden "if statements" which are never covered.
I guess what what you don't like about your answer is that you like to have a minimal code-coverage requirement for your code; I faced the same issue with some of my projects. If one must not lose the coverage data, one solution is to have "coverage build" where the problematic statements (assert, trace, etc.) are replaced with empty ones (say through macro or linker magic). But I believe this it is usually a better trade-off just to accept the non-perfect coverage.
Good luck.
Presumably you're using assertions to verify pre-conditions or some other set of conditions. Consider whether your situation is similar to Argument Exceptions should be Unit Tested.
In any case, I expect you're ultimately trying to determine if you should test the negative-path branches of these statements.
Yes, by all means, test those. Your assertions are themselves logic about your assumptions, and it's a Good Thing to test that your guard statements prevent/protect the scenarios you think they do.