Thinking about unit tests structure - java

I am thinking about how to write tests for my project. At the moment, tests structure is like this:
RealClass
{
method1;
method2;
...
}
and exactly same test class structure:
TestClass {
testMethod1;
testMethod2;
...
}
But, I do not like it, because I am putting too much test cases in one test method...
May be I should use structure like this:
TestClass {
testMethod1Opt1;
testMethod1Opt2;
...
testMethod2Opt1;
...}
How are you writing Unit tests?
Example of my test code: (Very simple test)
public void testIsAppUser() {
// My (Artem`s Zinnatullin) uId
final long artemZinnatullinUId = 172672179;
try {
assertTrue(usersApi.isAppUser(artemZinnatullinUId));
} catch (Exception e) {
fail(e.getMessage());
}
// Pavel`s Durov uId
final long durovUId = 1;
try {
assertFalse(usersApi.isAppUser(durovUId));
} catch (Exception e) {
fail(e.getMessage());
}
// By default uId == current user`s (who has authorized) uId
try {
assertTrue(usersApi.isAppUser(null));
} catch (Exception e) {
fail(e.getMessage());
}
}
What I am thinking about:
public void testIsAppUser1() {
// My (Artem`s Zinnatullin) uId
final long artemZinnatullinUId = 172672179;
try {
assertTrue(usersApi.isAppUser(artemZinnatullinUId));
} catch (Exception e) {
fail(e.getMessage());
}
}
public void testIsAppUser2() {
// Pavel`s Durov uId
final long durovUId = 1;
try {
assertFalse(usersApi.isAppUser(durovUId));
} catch (Exception e) {
fail(e.getMessage());
}
}
public void testIsAppUser3() {
// By default uId == current user`s (who has authorized) uId
try {
assertTrue(usersApi.isAppUser(null));
} catch (Exception e) {
fail(e.getMessage());
}
}
Give me advice please.

Comments:
Instead of try{} catch(){ fail() } just add throws Exception to the test method. JUnit will automatically fail the test for you and preserve the stack trace. This will make bug fixing much easier.
Create small test methods. That creates a name problem: How to come up with lots of good names? The solution here is to name the test after what it logically tests, not which methods it calls.
If you want to see what methods are called, use a code coverage tool like JaCoCo.
So the first test should be called testIsArtemsZinnatullinAppUser(). As a guideline: Whenever you feel like you need a comment to explain what a test does, the test name is wrong. Use whatever you'd write in the comment to create a test name.
The reason why you should have smaller tests is that JUnit stops for the first problem. So if you have 20 tests in one test case and the 3rd fails, 17 tests won't run. But these 17 tests could contain valuable information helping to figure out what is wrong.
If they all succeed, then this is probably a specific problem. If many tests fail, the problem must be in shared code.

Your second way of structuring the tests is a lot better. That way each test method covers a different way for the method to break, so you won't have the case where you fix one bug in a method, then have the test fail a little further down (so that one error prevents you from seeing others). It is a lot more important that the test methods be small and sharply-focused than that the test methods map to the methods of the object being tested.
Also, don't catch exceptions, JUnit will do that for you. Add throws Exception to the signature of each of your test methods. If you want to check that an exception is really thrown, then you can catch it in a test, like:
try {
objectUnderTest.doSomethingThatShouldThrowFooException();
fail("should've thrown an exception before getting here");
}
catch (FooException fooEx) {
// yay. my test passed
}
, but the boilerplate of:
} catch (Exception e) {
fail(e.getMessage());
}
is unnecessary.

I won't repeat what's in the other responses. But just adding this:
Avoid duplication of code construct in your test classes.
Don't hesitate to write explicit failure messages.
Here is something to illustrate what I mean:
public void testIsAppUser1() {
// My (Artem`s Zinnatullin) uId
assertAppUser(172672179,true,"artemZinnatullinUId");
}
public void testIsAppUser2() {
// Pavel`s Durov uId
assertAppUser(1,false,"Pavel`s Durov");
}
public void testIsAppUser3() {
// By default uId == current user`s (who has authorized) uId
assertAppUser(null,true,"current user");
}
private void assertAppUser(Long id, boolean isExpectedAppUser, String userName){
boolean isAppUser = usersApi.isAppUser(id);
if(isExpectedAppUser){
assertTrue("User with id:"+id+"and named:"+userName+" must be an appUser" ,isAppUser);
}else{
assertFalse("User with id:"+id+"and named:"+userName+" cannot be an appUser" ,isAppUser);
}
}
}

Only throw when you have an error that might happen because of an 'exception' don't necassarily throw because you can. The following assumes you are creating your own testing enviorment.
I don't know what your assert methods look like but really they should be the ones throwing if anything. You also don't need a try catch to throw an exception you can do the following:
throw new Exception("msg"); // Or another type of Exception
So implementation:
public void AssertEqual(Object obj1, Object obj2) throws Exception
{
if (!obj1.equals(obj2))
throw new Exception("Objects are not equal");
}

Related

JUnit /TestNG check for catched Exceptions

i have the following problem:
Our java software takes incoming xml-files and parse / validate / makes some magic. Because it's a 24/7 software it's designed to resist single faults, by ignoring single files and proceeding to the next.
I want to know if there is a possible solution to test units e.g with JUnit or TestNG for already catched exceptions.
For example if have a class and function like this
public class ExceptionTest {
public static void throwEx() {
try {
int i = 1 / 0;
} catch (Exception e) {
e.printStackTrace();
}
}
}
Now i want to test if any Exception is catched. If so the test should fail. On the other hand, if i expect certain types of exceptions, the test should succeed.
public class TSTException {
#Test
public void testExceptionThrown() {
ExceptionTest.throwEx();
assert ("ExceptionsCatched.size()", 0)
}
}
I know i could edit my code to provide some kind of global variables like boolean success = true and check those but i am interested if there is another possible solution for my problem.
Thanks,
Dominik
If it is possible to modify the code You could wrap the class containing the logic and catch the exception in the wrapper class.
something like this:
public class SomeService{
public void doSomething() {
int i = 1 / 0;
}
}
public class SomeServiceCatchExceptionWrapper{
private SomeService someService;
public void doSomething() {
try {
someService.doSomething();
} catch (Exception e) {
e.printStackTrace();
}
}
}
So this way you can test both classes individually.

Test multiple lines of codes w.r.t same Exception

I have a code segment like shown below. Each line of code throw same exception. However, in practice, when first line throws an exception, testFoo finishes its job and does not continue, as expected. But, I want a bit more different thing; since they are throwing same exception, I want to continue and check these three lines w.r.t the exception which they all throw. If they throw, test should be continue.
How can I test these three line w.r.t same exception?
#test
void testFoo(){
assertNull( /*errorMessage*/, ClassFoo.foo(null)); // foo will throw `AssertionError` due to null parameter
assertNull( /*errorMessage*/, ClassBar.bar(null)); // foo will throw `AssertionError` due to null parameter
assertNull( /*errorMessage*/, ClassGbr.gbr(null)); // foo will throw `AssertionError` due to null parameter
}
Just catch the exception yourself:
#Test
void testFoo() {
boolean fooHasThrownException = false;
boolean barHasThrownException = false;
boolean gbrHasThrownException = false;
try {
ClassFoo.foo(null);
fail();
} catch (AssertionError e) {
fooHasThrownException = true;
}
try {
ClassBar.bar(null);
fail();
} catch (AssertionError e) {
barHasThrownException = true;
}
try {
ClassGbr.gbr(null);
fail();
} catch (AssertionError e) {
gbrHasThrownException = true;
}
assertThat(true, equalTo(fooHasThrownException),
equalTo(barHasThrownException),
equalTo(gbrHasThrownException));
}
Note that your assertNull() is redundant. If a method throws an exception, it will not return anything.
On the side, this is a very weird scenario to be testing. If a method throws an exception, it just seems more logical to stop any further processing, if those processes down the line are going to also throw exceptions anyway.
I have tried to implement precondition for each parameters to a method with Java built-in Assert.assertTrue...
This is not built into java, this is from junit: void junit.framework.Assert.assertTrue(...). You are confusing Java Assertions with Junit assertions.
Junit assertions should be used in your unit tests. They look like Assert.assertEquals(result, "expected result"); They are intended to test the validity of the methods under test in your unit tests.
Java assertions should be used when verifying assumptions. They look like assert param!=null:"param should not be null!"; They are part of the java language and can be turned on and off at compile time. They are intended to double check assumptions in your code and to produce zero overhead when turned off.
Programming with assertions is a great thing. Using Junit assertions outside of unit tests is dubious.
My interpretation of this question is that you are expecting an AssertFailedError in your unit test and this is meant to be part of this test. If that is the case, you can use the following junit method structure:
#Test(expected = AssertFailedError.class)
public void testFoo() throws AssertFailedError
{
assertNotNull(null);
}
You can use this when you are testing a block of code that you know will throw an exception.

Is it possible to monitor handled exceptions using JUnit?

This is what I have:
#Test
public testSendMessageToStub() {
// under the hood sends message
// if exception occurrs
// it will be catched and message will be put on retry
object.sendMessage();
}
Is there any way to mark test as failed if exception has occurred but was handled in catch block in the sendMessage() method?
Thanks
EDIT: It seems like I was too fixated on these legacy tests and how they were used, that totally missed the fact of sendMessage returning a response with a status code (!!!). So now I just assert status codes, can expand these tests into more detailed scenarios and spin them on jenkins. I would like to avoid to answer how these tests were checked previously. The thought to check for status codes came to me after reading Plux's answer. Thanks!
Exactly what you are looking for is not possible with JUnit as far as I know.
If you really would want to test this, you could store some information about the exception in the catch-block where it is handled in the sendMessage() method.
A better option, in my opinion, could be to test the output or state of the object. If the state/output is exactly the same as when an exception doesn't occur, then whats the point of testing it? Do you have an overly broad catch-block?
EDIT: To AdityaTS, I dont have enough reputation to comment on a post, but my comment: you have not supplied all the code, so I can not say for sure, but my guess is that its the Logger.getLogger IN the catch-block that casts the ClassNotFoundException. (Either that or loadConnectionInfo()) see http://docs.oracle.com/javase/7/docs/api/java/lang/ClassNotFoundException.html
You cannot do this without modifying sendMessage method. If for example you catch the exception there but choose to ignore it and just return some value, code outside of the method doesn't know it. You can get around this by refactoring the code of object: move the code that handles the exception to a separate method, called e.g. handleException. Then, in your test you can create a subclass where handleException will execute the original handleException from superclass, but additionally set some flag which you will be able to read in your test and in this way tell that the exception was thrown. However, if you cannot modify the code for object's class, I'm afraid you're out of luck.
So you expect the exception to propagate out of the sendMessage() method, right?
This is another way to write a test that verifies an exception you expect will be thrown.
#Test (expected = MyExpectedException.class)
public testSendMessageToStub() {
// under the hood sends message
// if exception occurrs
// it will be catched and message will be put on retry
object.sendMessage();
}
And it's usually best to be as specific as possible (e.g. MyExpectedException.class over Exception.class)
The exception generated in the sendMessage() class will be available in the test method. Add a try catch block around the sendMessage() method like this
#Test
public testSendMessageToStub() {
try
{
object.sendMehssage();
}
catch(Excpetion e) //Use more specific exception type if you know
{
fail(e.getMessage());
}
}
I have tried this in my code. It worked for me. Let me know.
public DBConnectionInfo connectionInit()
{
loadConnectionInfo();
try
{
Class.forName(dbObject.getDriver());
} catch (Exception e)
{
Logger lgr = Logger.getLogger(PostgreLocationManager.class.getName());
lgr.log(Level.SEVERE, e.getMessage(), e);
}
try
{
dbObject.setConnection(DriverManager.getConnection(dbObject.getDatabaseURL(), dbObject.getUserName(),
dbObject.getPassword()));
} catch (Exception e)
{
Logger lgr = Logger.getLogger(PostgreLocationManager.class.getName());
lgr.log(Level.SEVERE, e.getMessage(), e);
}
return dbObject;
}
The test case for the above class.
#Test
public void testDriverFailure()
{
when(dbModelObject.getDriver()).thenReturn("driver");
when(dbModelObject.getDatabaseURL()).thenReturn("jdbc:postgresql://127.0.0.1:5432/testdb");
when(dbModelObject.getUserName()).thenReturn("postgres");
when(dbModelObject.getPassword()).thenReturn("postgres");
try
{
dbConnector.connectionInit();
} catch (Exception e)
{
assertTrue(e instanceof ClassNotFoundException);
}
verify(dbModelObject).getDriver();
}

JUnit MethodRule only tests one line

I've made an MethodRule and #Rule-annotation to make my test-life a bit easier.
It checks if a specific exception had been thrown and checks if the exception-message equals or contains the given message.
Now when i run a testmethod with more lines to test, it only takes the first line and than is ready. How do I make so all my lines in the testmethod are tested?
This is my code:
Annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface ExpectedDomeinValidatieMessage {
String value() default "";
String contains() default "";
}
MethodRule:
#Override
public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
ExpectedDomeinValidatieMessage message = method.getAnnotation(ExpectedDomeinValidatieMessage.class);
if (message == null) {
base.evaluate();
} else {
try {
base.evaluate();
Assert.fail("DomeinValidatieException not thrown");
} catch (DomeinValidatieException e) {
if (StringUtils.isNotBlank(message.value())) {
if (!e.getMessage().equals(message.value())) {
throwException(e, "", message.value(), e.getMessage());
}
}
if (StringUtils.isNotBlank(message.contains())) {
if (!e.getMessage().contains(message.contains())) {
throwException(e, "Segment niet gevonden:", message.contains(), e.getMessage());
}
}
}
}
}
private void throwException(Throwable exception, String message, String expected, String actual) {
ComparisonFailure cf = new ComparisonFailure(message, expected, actual);
cf.setStackTrace(exception.getStackTrace());
throw cf;
}
};
Usage:
#Test
#ExpectedDomeinValidatieMessage("[Werkzaamheden] WerkzaamMetGevaarlijkeStoffen niet gevuld")
public void valideerWerkzaamMetGevaarlijkeStoffen() throws DomeinValidatieException {
aanvraag.getVerzekerde().getWerkzaamheden().setWerkzaamMetGevaarlijkeStoffen(null);
validator.valideer();
}
If I use it like this, it only tests the first test in the method:
#Test
#ExpectedDomeinValidatieMessage("[Werkzaamheden] WerkzaamMetGevaarlijkeStoffen niet gevuld")
public void valideerWerkzaamMetGevaarlijkeStoffen() throws DomeinValidatieException {
aanvraag.getVerzekerde().getWerkzaamheden().setWerkzaamMetGevaarlijkeStoffen(null);
validator.valideer(); //Only this one is tested
aanvraag.getVerzekerde().getWerkzaamheden().setWerkzaamMetGevaarlijkeStoffen("bla");
validator.valideer(); //This is NOT tested
}
Run the code through a debugger. My guess is that the first call to valideer() does indeed throw an exception even though you don't expect it.
The JUnit assertXXX methods work by throwing exceptions (specifically AssertionError). So when an exception is thrown (either by your code, or by an assert) control exits from the test method. There isn't any way to restart from the place where the exception is thrown.
You probably want Parameterized, which allows you to run the same tests multiple times with different parameters.
EDIT: I suspect that valideer() is throwing an Exception. To explain a bit further, let's paraphrase your code. When you define a rule, what you're effectively doing is the following:
try {
base.evaluate(); // this calls valideerWerkzaamMetGevaarlijkeStoffen()
Assert.fail("DomeinValidatieException not thrown");
} catch (DomeinValidatieException e) {
// evaluate whether or not the test has failed or not
}
This means that if your first call to valideer() throws an Exception, then control is transferred to the catch block above. There isn't a chance to continue executing the test, because the control has passed elsewhere. You can pass/fail the test as much as you like, but control has passed to the catch block above.
By the way, MethodRule has been deprecated in the later versions, you should be using TestRule instead.

Is there a less-verbose way to silently ignore a specific nested exception in a Java unit test?

I have some unit tests which exercise code which makes calls out to a test server, in order to make sure that the requests are well-formed (i.e. we get valid data back in response). However, this means that the unit tests, and hence the build, can get blocked if this test server is down. This does not conform to good unit test practices, but as a thought experiment let's say I'm not allowed to delete these tests or change them so they don't actually call out to the server. I want to change them so that they will still pass if the server is down (i.e. trying to connect results in ConnectException), but fail if any other exception occurs. Making it more difficult, the code under test doesn't throw the ConnecException directly, but throws a wrapper exception that contains it. So initially, that means each test will go from looking like this:
#Test
public void testNumberOne() {
// body of test...
}
To this:
#Test
public void testNumberOne() {
try {
// body of test...
} catch (ThirdPartyWrapperException e) {
if (!(e.getRootCause() instanceof ConnectException) {
throw e;
}
}
}
Is there any way I can avoid having to paste that try/catch into each unit test?
I know I can refactor out at least some of it, ala:
#Test
public void testNumberOne() {
try {
// body of test...
} catch (ThirdPartyWrapperException e) {
handleException(e);
}
}
private void handleException(ThirdPartyWrapperException e)
throws ThirdPartyWrapperException {
if (!(e.getRootCause() instanceof ConnectException) {
throw e;
}
}
But is there anything further I can do?
I would add a line to the start to determine if the required resources are available
#Test
public void testNumberOne() {
if (!requiredServerAvailable()) return;

Categories