Is it possible to bypass certain exception in unit test? - java

Is it even possible to bypass certain exceptions in mockito? This sounds crazy. You want to catch expected exceptions in the unit testing I assume. However I decided to give a try asking this question. Here is my scenario hope I could improve my understanding on mockito and general unit test principals via this.
I have to build a simple unit test for a particular class Foo in an enterprise web application using mockito unit test framework.
This Foo class requires ldap and database connections however due to a reason, I can not use development environment specific ldap and database in the unit test.
I just need to test part accessing ldap so that I decided to use unboundid in memory ldap which allows to create light weight directory at run time and remove it from memory after testing is done.
My question is during the instantiation of Foo class via #InjectedMocks annotation, it triggers chain reaction of calling many other classes and their methods. It threw many exceptions which I expected.
I am trying to find a way to somehow ignore some specific exceptions such as loading/reading environment specific properties files or database access and etc.
For my goal, I don't need reading prop files nor database access.
I read upon ExpectedException junit provides which is subset of mockito if I am not mistaken however I don't think its aim aligns with my intention of bypassing some of the exceptions. I could be wrong on this.
All I want to accomplish is:
Instantiate Foo class
Call one of its methods that would read a list of group from In memory ldap
Verify returned data
Here is water downed version of test class:
#RunWith(MockitoJUnitRunner.class)
public class FooTest {
private static InMemoryDirectoryServer ldapServer;
private static Integer ldapPort = xxxxx;
#InjectedMocks
Foo footester = Foo.getInstance();
#BeforeClass
public static void setUpBeforeClass() {
try {
// execute instantiate in memory ldap..
} catch (Exception e) {
// do print out
}
}
#Test
public void testLdap() {
// before it reaches here exceptions were thrown
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
// do tear down execution
}
}

You can catch an exception like this:
#Test(expected = YourExceptionHere.class)
public void testSomething()
{
foo(FOO_VALUE);
}

Related

How to verify in Mockito if the entity class setter is not called [duplicate]

I know that one way to do it would be:
#Test
public void foo() {
try {
// execute code that you expect not to throw Exceptions.
} catch(Exception e) {
fail("Should not have thrown any exception");
}
}
Is there any cleaner way of doing this? (Probably using Junit's #Rule?)
You're approaching this the wrong way. Just test your functionality: if an exception is thrown the test will automatically fail. If no exception is thrown, your tests will all turn up green.
I have noticed this question garners interest from time to time so I'll expand a little.
Background to unit testing
When you're unit testing it's important to define to yourself what you consider a unit of work. Basically: an extraction of your codebase that may or may not include multiple methods or classes that represents a single piece of functionality.
Or, as defined in The art of Unit Testing, 2nd Edition by Roy Osherove, page 11:
A unit test is an automated piece of code that invokes the unit of work being tested, and then checks some assumptions about a single end result of that unit. A unit test is almost always written using a unit testing framework. It can be written easily and runs quickly. It's trustworthy, readable, and maintainable. It's consistent in its results as long as production code hasn't changed.
What is important to realize is that one unit of work usually isn't just one method but at the very basic level it is one method and after that it is encapsulated by other unit of works.
Ideally you should have a test method for each separate unit of work so you can always immediately view where things are going wrong. In this example there is a basic method called getUserById() which will return a user and there is a total of 3 unit of works.
The first unit of work should test whether or not a valid user is being returned in the case of valid and invalid input.
Any exceptions that are being thrown by the datasource have to be handled here: if no user is present there should be a test that demonstrates that an exception is thrown when the user can't be found. A sample of this could be the IllegalArgumentException which is caught with the #Test(expected = IllegalArgumentException.class) annotation.
Once you have handled all your usecases for this basic unit of work, you move up a level. Here you do exactly the same, but you only handle the exceptions that come from the level right below the current one. This keeps your testing code well structured and allows you to quickly run through the architecture to find where things go wrong, instead of having to hop all over the place.
Handling a tests' valid and faulty input
At this point it should be clear how we're going to handle these exceptions. There are 2 types of input: valid input and faulty input (the input is valid in the strict sense, but it's not correct).
When you work with valid input you're setting the implicit expectancy that whatever test you write, will work.
Such a method call can look like this: existingUserById_ShouldReturn_UserObject. If this method fails (e.g.: an exception is thrown) then you know something went wrong and you can start digging.
By adding another test (nonExistingUserById_ShouldThrow_IllegalArgumentException) that uses the faulty input and expects an exception you can see whether your method does what it is supposed to do with wrong input.
TL;DR
You were trying to do two things in your test: check for valid and faulty input. By splitting this into two method that each do one thing, you will have much clearer tests and a much better overview of where things go wrong.
By keeping the layered unit of works in mind you can also reduce the amount of tests you need for a layer that is higher in the hierarchy because you don't have to account for every thing that might have gone wrong in the lower layers: the layers below the current one are a virtual guarantee that your dependencies work and if something goes wrong, it's in your current layer (assuming the lower layers don't throw any errors themselves).
JUnit 5 (Jupiter) provides three functions to check exception absence/presence:
● assertAll​()
  Asserts that all supplied executables
  do not throw exceptions.
● assertDoesNotThrow​()
  Asserts that execution of the
  supplied executable/supplier
  does not throw any kind of exception.
  This function is available
  since JUnit 5.2.0 (29 April 2018).
● assertThrows​()
  Asserts that execution of the supplied executable
  throws an exception of the expectedType
  and returns the exception.
Example
package test.mycompany.myapp.mymodule;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class MyClassTest {
#Test
void when_string_has_been_constructed_then_myFunction_does_not_throw() {
String myString = "this string has been constructed";
assertAll(() -> MyClass.myFunction(myString));
}
#Test
void when_string_has_been_constructed_then_myFunction_does_not_throw__junit_v520() {
String myString = "this string has been constructed";
assertDoesNotThrow(() -> MyClass.myFunction(myString));
}
#Test
void when_string_is_null_then_myFunction_throws_IllegalArgumentException() {
String myString = null;
assertThrows(
IllegalArgumentException.class,
() -> MyClass.myFunction(myString));
}
}
I stumbled upon this because of SonarQube's rule "squid:S2699": "Add at least one assertion to this test case."
I had a simple test whose only goal was to go through without throwing exceptions.
Consider this simple code:
public class Printer {
public static void printLine(final String line) {
System.out.println(line);
}
}
What kind of assertion can be added to test this method?
Sure, you can make a try-catch around it, but that is only code bloat.
The solution comes from JUnit itself.
In case no exception is thrown and you want to explicitly illustrate this behaviour, simply add expected as in the following example:
#Test(expected = Test.None.class /* no exception expected */)
public void test_printLine() {
Printer.printLine("line");
}
Test.None.class is the default for the expected value.
If you import org.junit.Test.None, you can then write:
#Test(expected = None.class)
which you might find more readable.
For JUnit versions before 5:
With AssertJ fluent assertions 3.7.0:
Assertions.assertThatCode(() -> toTest.method())
.doesNotThrowAnyException();
Update:
JUnit 5 introduced assertDoesNotThrow() assertion, so I'd prefer to use it instead of adding an additional dependency to your project. See this answer for details.
Java 8 makes this a lot easier, and Kotlin/Scala doubly so.
We can write a little utility class
class MyAssertions{
public static void assertDoesNotThrow(FailingRunnable action){
try{
action.run()
}
catch(Exception ex){
throw new Error("expected action not to throw, but it did!", ex)
}
}
}
#FunctionalInterface interface FailingRunnable { void run() throws Exception }
and then your code becomes simply:
#Test
public void foo(){
MyAssertions.assertDoesNotThrow(() -> {
//execute code that you expect not to throw Exceptions.
}
}
If you dont have access to Java-8, I would use a painfully old java facility: aribitrary code blocks and a simple comment
//setup
Component component = new Component();
//act
configure(component);
//assert
/*assert does not throw*/{
component.doSomething();
}
And finally, with kotlin, a language I've recently fallen in love with:
fun (() -> Any?).shouldNotThrow()
= try { invoke() } catch (ex : Exception){ throw Error("expected not to throw!", ex) }
#Test fun `when foo happens should not throw`(){
//...
{ /*code that shouldn't throw*/ }.shouldNotThrow()
}
Though there is a lot of room to fiddle with exactly how you want to express this, I was always a fan of fluent assertions.
Regarding
You're approaching this the wrong way. Just test your functionality: if an exception is thrown the test will automatically fail. If no exception is thrown, your tests will all turn up green.
This is correct in principle but incorrect in conclusion.
Java allows exceptions for flow of control. This is done by the JRE runtime itself in APIs like Double.parseDouble via a NumberFormatException and Paths.get via a InvalidPathException.
Given you've written a component that validates Number strings for Double.ParseDouble, maybe using a Regex, maybe a hand-written parser, or perhaps something that embeds some other domain rules that restricts the range of a double to something specific, how best to test this component? I think an obvious test would be to assert that, when the resulting string is parsed, no exception is thrown. I would write that test using either the above assertDoesNotThrow or /*comment*/{code} block. Something like
#Test public void given_validator_accepts_string_result_should_be_interpretable_by_doubleParseDouble(){
//setup
String input = "12.34E+26" //a string double with domain significance
//act
boolean isValid = component.validate(input)
//assert -- using the library 'assertJ', my personal favourite
assertThat(isValid).describedAs(input + " was considered valid by component").isTrue();
assertDoesNotThrow(() -> Double.parseDouble(input));
}
I would also encourage you to parameterize this test on input using Theories or Parameterized so that you can more easily re-use this test for other inputs. Alternatively, if you want to go exotic, you could go for a test-generation tool (and this). TestNG has better support for parameterized tests.
What I find particularly disagreeable is the recommendation of using #Test(expectedException=IllegalArgumentException.class), this exception is dangerously broad. If your code changes such that the component under test's constructor has if(constructorArgument <= 0) throw IllegalArgumentException(), and your test was supplying 0 for that argument because it was convenient --and this is very common, because good generating test data is a surprisingly hard problem--, then your test will be green-bar even though it tests nothing. Such a test is worse than useless.
If you are unlucky enough to catch all errors in your code.
You can stupidly do
class DumpTest {
Exception ex;
#Test
public void testWhatEver() {
try {
thisShouldThrowError();
} catch (Exception e) {
ex = e;
}
assertEquals(null,ex);
}
}
Although this post is 6 years old now, however, a lot has changed in the Junit world. With Junit5, you can now use
org.junit.jupiter.api.Assertions.assertDoesNotThrow()
Ex:
public void thisMethodDoesNotThrowException(){
System.out.println("Hello There");
}
#Test
public void test_thisMethodDoesNotThrowException(){
org.junit.jupiter.api.Assertions.assertDoesNotThrow(
()-> thisMethodDoesNotThrowException()
);
}
Hope it will help people who are using newer version of Junit5
JUnit5 adds the assertAll() method for this exact purpose.
assertAll( () -> foo() )
source: JUnit 5 API
To test a scenario with a void method like
void testMeWell() throws SomeException {..}
to not throw an exception:
Junit5
assertDoesNotThrow(() -> {
testMeWell();
});
If you want to test that whether your test target consumes the exception. Just leave the test as (mock collaborator using jMock2):
#Test
public void consumesAndLogsExceptions() throws Exception {
context.checking(new Expectations() {
{
oneOf(collaborator).doSth();
will(throwException(new NullPointerException()));
}
});
target.doSth();
}
The test would pass if your target does consume the exception thrown, otherwise the test would fail.
If you want to test your exception consumption logic, things get more complex. I suggest delegating the consumption to a collaborator which could be mocked. Therefore the test could be:
#Test
public void consumesAndLogsExceptions() throws Exception {
Exception e = new NullPointerException();
context.checking(new Expectations() {
{
allowing(collaborator).doSth();
will(throwException(e));
oneOf(consumer).consume(e);
}
});
target.doSth();
}
But sometimes it's over-designed if you just want to log it. In this case, this article(http://java.dzone.com/articles/monitoring-declarative-transac, http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there-an-easy-way/) may help if you insist tdd in this case.
Use assertNull(...)
#Test
public void foo() {
try {
//execute code that you expect not to throw Exceptions.
} catch (Exception e){
assertNull(e);
}
}
This may not be the best way but it definitely makes sure that exception is not thrown from the code block that is being tested.
import org.assertj.core.api.Assertions;
import org.junit.Test;
public class AssertionExample {
#Test
public void testNoException(){
assertNoException();
}
private void assertException(){
Assertions.assertThatThrownBy(this::doNotThrowException).isInstanceOf(Exception.class);
}
private void assertNoException(){
Assertions.assertThatThrownBy(() -> assertException()).isInstanceOf(AssertionError.class);
}
private void doNotThrowException(){
//This method will never throw exception
}
}
I faced the same situation, I needed to check that exception is thrown when it should, and only when it should.
Ended up using the exception handler to my benefit with the following code:
try {
functionThatMightThrowException()
}catch (Exception e){
Assert.fail("should not throw exception");
}
RestOfAssertions();
The main benefit for me was that it is quite straight forward and to check the other way of the "if and only if" is really easy in this same structure
I end up doing like this
#Test
fun `Should not throw`() {
whenever(authService.isAdmin()).thenReturn(true)
assertDoesNotThrow {
service.throwIfNotAllowed("client")
}
}
You can expect that exception is not thrown by creating a rule.
#Rule
public ExpectedException expectedException = ExpectedException.none();
You can do it by using a #Rule and then call method reportMissingExceptionWithMessage as shown below:
This is Scala code.
Stumbled over this issue since I created some generic methods like
#Test
void testSomething() {
checkGeneric(anComplexObect)
}
In https://newbedev.com/sonarqube-issue-add-at-least-one-assertion-to-this-test-case-for-unit-test-with-assertions some annotation stuff is proposed.
The solution is much more simple. It's enough to rename the "checkGeneric" method to "assertGeneric".
#Test
void testSomething() {
assertGeneric(anComplexObect)
}
You can create any kind of your own assertions based on assertions from junit, because these are especially designed for creating user defined asserts intendet to work exactly like junit ones:
static void assertDoesNotThrow(Executable executable) {
assertDoesNotThrow(executable, "must not throw");
}
static void assertDoesNotThrow(Executable executable, String message) {
try {
executable.execute();
} catch (Throwable err) {
fail(message);
}
}
Now testing the so called scenario methodMustNotThrow and log all failures in a junit style:
//test and log with default and custom messages
//the following will succeed
assertDoesNotThrow(()->methodMustNotThrow(1));
assertDoesNotThrow(()->methodMustNotThrow(1), "custom facepalm");
//the following will fail
assertDoesNotThrow(()->methodMustNotThrow(2));
assertDoesNotThrow(()-> {throw new Exception("Hello world");}, "message");
//See implementation of methodMustNotThrow below
Generally speaking there is possibility to instantly fail anything the test in any scenarios, in any place where it makes sense by calling fail(someMessage), which is designed exactly for this purpose. For instance use it in a try/catch block to fail if anything is thrown in the test case:
try{methodMustNotThrow(1);}catch(Throwable e){fail("must not throw");}
try{methodMustNotThrow(1);}catch(Throwable e){Assertions.fail("must not throw");}
This is the sample of the method we test, supposing we have such a method that must not fail under specific circumstances, but it can fail:
void methodMustNotThrow(int x) throws Exception {
if (x == 1) return;
throw new Exception();
}
The above method is a simple sample. But this works for complex situations, where the failure is not so obvious.
There are the imports:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import static org.junit.jupiter.api.Assertions.*;
AssertJ can handle this scenario:
assertThatNoException().isThrownBy(() -> System.out.println("OK"));
Check the doc for more information https://assertj.github.io/doc/#assertj-core-exception-assertions-no-exception
The following fails the test for all exceptions, checked or unchecked:
#Test
public void testMyCode() {
try {
runMyTestCode();
} catch (Throwable t) {
throw new Error("fail!");
}
}

How to make the unit test execute a particular test case everytime when it sees a certain function in the executing java project?

I am having a build failure issue while running a bunch of unit test over a java project. I am getting the NoClassDefFoundError which is happening because of the lack of ability for the unit test to get the dependencies. I am trying to mock an object for the class and then call the function, but the code is structured in a way that is getting a bit complex for me to handle the issue. I am very new to unit testing. I have provided below, a sample of code structure that my project has
Class ServiceProvider(){
obj declarations;
public void mainFunction(){
//Does a couple of things and calls a function in another class
boolean val = subFunction();
}
public boolean subFunction(){
boolean val = AnotherClass.someFunction(text);
//this function throws lots of exceptions and all those are caught and handled
return val;
}
#RunsWith(MockitoJUnitRunner.class)
Class UnitTestBunch(){
#Mock
AnotherClass acObj = new AnotherClass();
#InjectMock
ServiceProvider sp = new ServiceProvider();
#Test
public void unitTest1() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
#Test
public void unitTest2() throws Exception{
thrown.expect(ExceptionName.Class);
sp.mainFunction();
}
I have a test that uses the mock object and performs the function call associated with that class. But, the issue here is that there are a bunch of other unit test cases that are written similar to the unitTest2 function and calls the mainFunction at the end of the test. This mainFunction invokes someFunction() and causes NoCalssDefFoundError(). I am trying to make the unit test execute the content in unitTest1 everytime when it sees the AnotherClass.someFunction(). I am not sure if this is achievable or not. There could be another better way to resolve this issue. Could someone please pitch in some ideas?
In your test you seem to be using unitTest1 for setup, not for testing anything. When you run a unit test, each test should be able to run separately or together, in any order.
You're using JUnit4 in your tests, so it would be very easy to add the statement you have in unitTest1 into a #Before method. JUnit4 will call this method before each test method (annotated with #Test).
#Before
public void stubAcObj() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
The method may be named anything, though setUp() is a common name borrowed from a method to override in JUnit3. However, it must be annotated with org.junit.Before.
If you need this from multiple test cases, you should just create a helper, as you would with any code. This doesn't work as well with #InjectMocks, but you may want to avoid using #InjectMocks in general as it will fail silently if you add a dependency to your system-under-test.
public class AnotherClassTestHelper {
/** Returns a Mockito mock of AnotherClass with a stub for someFunction. */
public static AnotherClass createAnotherClassMock() {
AnotherClass mockAnotherClass = Mockito.mock(AnotherClass.class);
when(mockAnotherClass.someFunction(text)).thenReturn(true);
return mockAnotherClass;
}
}
As a side note, this is a counterintuitive pattern:
/* BAD */
#Mock
AnotherClass acObj = new AnotherClass();
You create a new, real AnotherClass, then instruct Mockito to overwrite it with a mock (in MockitoJUnitRunner). It's much better just to say:
/* GOOD */
#Mock AnotherClass acObj;

How to write unit test by mocking, when you have zero arg:constructors

I was trying to write unit test using jmocks and junit. (My Project uses core java- no frameworks-) I could not write unit test for some of my classes, by mocking external dependencies, when dependencies were initialized in a a no arg-constructor.
As i cannot provide the actual code, trying to explain the scenario by an example
public interface Apple {
String variety();
}
Implementation.
public class MalgovaApple implements Apple {
#Override
public String variety() {
return "Malgova";
}
}
Class to be tested
public class VarietyChecker {
private Apple apple;
VarietyChecker(){
this.apple = new MalgovaApple();
// instead of new, a factory method is used in actual application
}
public String printAppleVariety(){
String variety = apple.variety();
if(variety.length() < 3){
System.out.println("Donot use Code names- Use complete names");
return "bad";
}
return "good";
}
}
Junit test using jmock
public class VarietyCheckerUnitTest{
Mockery context = new JUnit4Mockery();
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void test_VarietyChecker() throws Exception{
final Apple mockapple = context.mock(Apple.class);
VarietyChecker printer = new VarietyChecker();
context.checking(new Expectations(){{
oneOf(mockapple).variety();will(returnValue("as"));
}});
String varietyNameValid = printer.printAppleVariety();
assertEquals("bad",varietyNameValid);
} }
This test fails - Mocking does not work the values "as" is not injected, the test class executes with MalgovaApple ...
Now if we add below constructor to VarietyChecker and use it test case - it gives expected output...
public VarietyChecker(Apple apple) {
super();
this.apple = apple;
}
and in unit test create test class object like
VarietyChecker printer = new VarietyChecker(mockapple);
Exposing a new constructor just for the purpose of testing is not a good idea. After all it is said that you should not alter the code for testing alone, more than that, i am afraid we have already written "some"(amount) code...
Am i missing something in junit or jmock that can make mocking work even incase of no-arg constructors. Or is this a limitation of simple junit and jmocks and should i migrate to something powerful like Jmockit /PowerMock
You should consider two choices.
Use a constructor parameter as you describe.
In this case, you're not "exposing a new constructor just for the purpose of testing". You're making your class more flexible by allowing callers to use a different factory implementation.
Don't mock it.
In this case, you are declaring that it never makes sense to use a different factory. Sometimes this is okay. At that point, the question changes, though. Instead of, "How do I mock this?" your question is now, "What am I gaining from writing this test?" You might not be gaining much of anything, and it might not make much sense to write the test at all.
If you don't mock it and decide a unit test is still worth it, then you should be asserting on other aspects of the code. Either an end state or some output. In this case, the factory call becomes an implementation detail that's not appropriate for mocking.
It's important not to fall for a "unit test everything" mentality. That is a recipe for Test-induced Design Damage. Evaluate your tests on a case by case basis, deciding whether they're providing you any real value or not. Not writing a unit test is a valid option and is even appropriate at times, even if it's option you try very hard to avoid.
Only you can make a determination which one makes the most sense in this case. From the the fact that this is a factory object we're talking about, I'd probably lean toward the former.

JUnit Test of Code that uses GAE/J URLFetchServiceFactory.getURLFetchService()

I've got some code I'm deploying to Google App Engine - Java (GAE/J) that makes use of the URLFetchService. I'd like to use JUnit to test this code. Per the testing documentation, it appears I should have a test that uses their LocalURLFetchServiceTestConfig class ROUGHLY as follows:
public class MyRemoteServiceTests {
private static final LocalURLFetchServiceTestConfig urlConfig = new LocalURLFetchServiceTestConfig();
private static final LocalServiceTestHelper helper =
new LocalServiceTestHelper(urlConfig);
#Before
public void setUp() throws Exception {
service = new SampleService();
helper.setUp();
}
#After
public void tearDown() throws Exception {
service = null;
helper.tearDown();
}
#Test
public void testThatCallsCodeThatUsesUrlFetch() {
Object data = service.getRemoteDataUsingUrlFetch("foo", "bar");
Assert.assertNotNull(data);
}
}
I'm finding that this test continues to fail despite using the "helper" as suggested in the GAE/J documentation on testing: "The API package 'urlfetch' or call 'Fetch()' was not found.".
I was assuming that using the "helper" would somehow setup the GAE environment such that when I call URLFetchServiceFactory.getURLFetchService() from within my getRemoteDataUsingUrlFetch method, the interface returned would be an instance of LocalURLFetchService that would just "work" but that seems NOT to be the case.
How can I test this code?
Am I missing something? (I'm pretty new to GAE...)
Do I have to refactor my getRemoteDataUsingUrlFetch so that it doesn't use URLFetchServiceFactory.getURLFetchService() because that makes it untestable locally??? (That sounds like it would really suck...)
Any help/suggestions much appreciated!
Actually, it turns out my problem was failure to include two additional jars that ARE mentioned on the Local Unit Testing page of the documentation. RTM FTW!
appengine-local-runtime.jar
appengine-api-stubs.jar
afaik, the LocalURLFetchService doesn't configure the GAE like you expect. It is more of a way to fetch URL from the local dev and then process the contents however. (Similarly even the LocalDatastoreService and LocalMemcacheService operate on isolated spaces within the test environment)
One way to test your code is to refactor the getRemoteDataUsingUrlFetch() to take maybe the contents of the Url response. somewhat like,
URLFetchResponse resp = LocalURLFetchService.fetch(status, request)
getRemoteDataUsingUrlFetch(foo, bar, resp)

How to do unit test for Exceptions?

As you know, exception is thrown at the condition of abnormal scenarios. So how to analog these exceptions? I feel it is challenge. For such code snippets:
public String getServerName() {
try {
InetAddress addr = InetAddress.getLocalHost();
String hostname = addr.getHostName();
return hostname;
}
catch (Exception e) {
e.printStackTrace();
return "";
}
}
Does anybody have good ideas?
You can tell junit that the correct behavior is to get an exception.
In JUnit 4, it goes something like:
#Test(expected = MyExceptionClass.class)
public void functionUnderTest() {
…
}
Other answers have addressed the general problem of how to write a unit test that checks that an exception is thrown. But I think your question is really asking about how to get the code to throw the exception in the first place.
Take your code as an example. It would be very hard to cause your getServerName() to internally throw an exception in the context of a simple unit test. The problem is that in order for the exception to happen, the code (typically) needs to be run on a machine whose networking is broken. Arranging for that to happen in a unit test is probably impossible ... you'd need to deliberately misconfigure the machine before running the test.
So what is the answer?
In some cases, the simple answer is just to take the pragmatic decision and not go for total test coverage. Your method is a good example. It should be clear from code inspection what the method actually does. Testing it is not going to prove anything (except see below **). All you are doing is improve your test counts and test coverage numbers, neither of which should be project goals.
In other cases, it may be sensible to separate out the low-level code where the exception is being generated and make it a separate class. Then, to test the higher level code's handling of the exception, you can replace the class with a mock class that will throw the desired exceptions.
Here is your example given this "treatment". (This is a bit contrived ... )
public interface ILocalDetails {
InetAddress getLocalHost() throws UnknownHostException;
...
}
public class LocalDetails implements ILocalDetails {
public InetAddress getLocalHost() throws UnknownHostException {
return InetAddress.getLocalHost();
}
}
public class SomeClass {
private ILocalDetails local = new LocalDetails(); // or something ...
...
public String getServerName() {
try {
InetAddress addr = local.getLocalHost();
return addr.getHostName();
}
catch (Exception e) {
e.printStackTrace();
return "";
}
}
}
Now to unit test this, you create a "mock" implementation of the ILocalDetails interface whose getLocalHost() method throws the exception you want under the appropriate conditions. Then you create a unit text for SomeClass.getServerName(), arranging that the instance of SomeClass uses an instance of your "mock" class instead of the normal one. (The last bit could be done using a mocking framework, by exposing a setter for the local attribute or by using the reflection APIs.)
Obviously, you would need to modify your code to make it testable like this. And there are limits to what you can do ... for example, you now cannot create a unit test to make the real LocalDetails.getLocalHost() method to throw an exception. You need to make a case-by-case judgement as to whether it is worth the effort of doing this; i.e. does the benefit of the unit test outweigh the work (and extra code complexity) of making the class testable in this way. (The fact that there is a static method at the bottom of this is a large part of the problem.)
** There is a hypothetical point to this kind of testing. In your example, the fact that the original code catches an exception and returns an empty string could be a bug ... depending on how the method's API is specified ... and a hypothetical unit test would pick it up. However, in this case, the bug is so blatant that you would spot it while writing the unit test! And assuming that you fix bugs as you find them, the unit test becomes somewhat redundant. (You wouldn't expect someone to re-instate this particular bug ...)
Okay there are a few possible answers here.
Testing for an exception itself is easy
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
#Test
public void TestForException() {
try {
doSomething();
fail();
} catch (Exception e) {
assertThat(e.getMessage(), is("Something bad happened"));
}
}
Alternately, you can use the Exception Annotation to note that you expect an exception to come out.
Now, as to you specific example, Testing that something you are creating inside your method, either via new or statically as you did, when you have no way to interact with the object is tricky. You normally need to encapsulate that particular generator and then use some mocking to be able to override the behavior to generate the exception you expect.
Since this question is in community wiki I'll add a new one for completeness:
You can use ExpectedException in JUnit 4
#Rule
public ExpectedException thrown= ExpectedException.none();
#Test
public void TestForException(){
thrown.expect(SomeException.class);
DoSomething();
}
The ExpectedException makes the thrown exception available to all test methods.
Is is also possible to test for a specific error message:
thrown.expectMessage("Error string");
or use matchers
thrown.expectMessage(startsWith("Specific start"));
This is shorter and more convenient than
public void TestForException(){
try{
DoSomething();
Fail();
}catch(Exception e) {
Assert.That(e.msg, Is("Bad thing happened"))
}
}
because if you forget the fail, the test can result in a false negative.
Many unit testing frameworks allow your tests to expect exceptions as part of the test. JUnit, for example, allows for this.
#Test (expected=IndexOutOfBoundsException.class) public void elementAt() {
int[] intArray = new int[10];
int i = intArray[20]; // Should throw IndexOutOfBoundsException
}

Categories