2

Can you please help me better understand, what is an appropriate use of “assert” vs “throwing an exception? When is each scenario appropriate?

Scenario 1

CODE

public Context(Algorythm algo) {
  if (algo == null) {
      throw new IllegalArgumentException("Failed to initialize Context");
  }
  this.algo = algo;
}

TEST

public void testContext_null() {
  try {
      context = new Context(null);
      fail();
  } catch (IllegalArgumentException e) {
      assertNotNull(e);
  }
}

Scenario 2

CODE

public Context(Algorythm algo) {
  assert (algo != null);
  this.algo = algo;
}

TEST

public void testContext_null() {
  try {
      context = new Context(null);
      fail();
  } catch (AssertionFailedError e) {
      assertNotNull(e);
  }
}
James Raitsev
  • 92,517
  • 154
  • 335
  • 470
  • You cannot catch a null exception. assertNotNull(e) has to be true. – Peter Lawrey Dec 03 '10 at 15:49
  • 1
    Are you using JUnit 4? If you are, use the `@Test(expected=IllegalArgumentException.class)` annotation instead of having `try`/`catch` in your test method. – Asaph Dec 03 '10 at 15:51
  • And the fail(); or the test might pass for the wrong reason. – Peter Lawrey Dec 03 '10 at 15:52
  • @Asaph - good point. I totally forgot about that. Thx – James Raitsev Dec 03 '10 at 15:53
  • @Peter. The issue is not with assertNotNull, but rather using general Java's "assert" statement vs writing up an "if" condition where if it fails exception is thrown – James Raitsev Dec 03 '10 at 15:54
  • Doing this right in JUnit 4, the body of the test method becomes a 1 liner. Like this: `@Test(expected=IllegalArgumentException.class) public void testContext_null() { new Context(null); }` – Asaph Dec 03 '10 at 15:54
  • @mac: What version of JUnit are you using? – Asaph Dec 03 '10 at 16:16
  • I figured it out ... weird thing actually. Initially i just added jUnit4.8.2 jar into my class. This caused the error. Once i added a JUnit Library" everything worked. I am a bit confused now. I thought having added "external jar to classpath" does it. – James Raitsev Dec 03 '10 at 16:23
  • Ok, really weird. In order to remove all errors - i removed "extends TestCase" from my jUnit class, added jUnit Library and voila- everything is working. Is "extends TestCase" not needed for Junit4? – James Raitsev Dec 03 '10 at 16:38
  • http://stackoverflow.com/questions/2635839/junit-confusion-use-extend-testcase-or-test answers it all. Thanks again everyone. – James Raitsev Dec 03 '10 at 16:44

4 Answers4

5

The main difference with assert is;

  • the ability to turn on/off selected tests by class/package.
  • the error thrown.

assert is more approriate for tests which will be turned off in production.

If you want a test which is checked every time, esp if validating data from an input, you should use the check which runs every time.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

Assert is a macro (in C/C++, or a function in other languages) that validates a given expression as true or false, and throw an exception in case of false values.

Assert is something to use when ddebugging an application, like when you must check if a math expression really gives you an appropriate value, or if an object/structure member is not null or missing something important, and things like that.

An Exception throwing is more of a real error treatment. Exceptions are errors too and can stop your application, but they are used as the (let's say) "retail version" error treatment of the application. That's because Exceptions can be caught and taken differently to the user, with a little non-technical message instead of symbols and memory addresses, while you can just serialize that into an app log, for example.

On the other hand, asserts will just stop the running process and give you a message like "Assertion failed on source_file.ext, line X. The process will be terminated." And that's not user-friendly :)

Giuliano
  • 172
  • 9
0

The assert keyword should be used when failure to meet a condition violates the integrity of the program. These are intended to be non-recoverable error situations.

Exceptions, on the other hand, alert calling methods to the presence and location of an error but can be handled or ignored at the programmer's discretion.

When testing, you should use the Assert functions when a condition must be met for a test to pass. If you're expecting an exception in that particular test, JUnit 4 has an annotation to signify that an test should throw a particular Exception:

@Test(expected=MyException.class)
01001111
  • 838
  • 5
  • 5
0

Outside of test code, asserts are generally a bad idea. the reason is that unless there are very strict company guidelines in place, you invariably end up with mixed usage, which is bad. there are basically 2 usage scenarios for assert:

  1. extra, possibly slow tests which will be turned off in production
  2. normal, quick code sanity tests which should never be disabled (like requiring a given method parameter to be non-null)

As long as you always follow one of the scenarios, things are fine. however, if your code base ends up with both scenarios, then you are stuck. you have asserts which follow scenario 2 which you don't want to disable, and you have asserts which follow scenario 1 (and are slowing down your production code) which you want to disable. what to do?

most codebases which i have worked with which used asserts in normal code, never ended up disabling them in the production build for exactly this reason. therefore, my recommendation is always to avoid them outside of test code. use normal exceptions for the normal code, and stick the extra, possibly slow code (with asserts) in separate test code.

james
  • 1,230
  • 9
  • 4