239

Is it possible in JUnit to assert an object is an instance of a class? For various reasons I have an object in my test that I want to check the type of. Is it a type of Object1 or a type of Object2?

Currently I have:

assertTrue(myObject instanceof Object1);
assertTrue(myObject instanceof Object2);

This works but I was wondering if there is a more expressive way of doing this.

For example something like:

assertObjectIsClass(myObject, Object1);

I could do this:

assertEquals(myObject.class, Object1.getClass());

Is there a specific assert method that allows me to test a type of an object in a more elegant, fluid manner?

TheZ
  • 3,663
  • 19
  • 34
RNJ
  • 15,272
  • 18
  • 86
  • 131
  • 21
    Are you aware that `assertTrue(myObject instanceof Object1);` and `assertEquals(myObject.class, Object1.getClass());` are actually different tests? The first accepts myObject being an instance of a subclass of `Object1`, the later doesn't. – Erich Kitzmueller Sep 13 '12 at 10:59
  • @ammoQ Very good point. I didnt think of subclasses. Thanks for the clarifaction – RNJ Sep 13 '12 at 11:04
  • 1
    as maba points out, consider using Hamcrest. This is more than just so that you have a better working test. Hamcrest also provides much better logging of the failure than standard `assertTrue`. `assertTrue` would just say `expected true got false`, Hamcrest would say `expected instanced of XYZ, got instance of ABC` – John B Sep 13 '12 at 11:14

6 Answers6

292

You can use the assertThat method and the Matchers that comes with JUnit.

Take a look at this link that describes a little bit about the JUnit Matchers.

Example:

public class BaseClass {
}

public class SubClass extends BaseClass {
}

Test:

import org.junit.Test;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertThat;

/**
 * @author maba, 2012-09-13
 */
public class InstanceOfTest {

    @Test
    public void testInstanceOf() {
        SubClass subClass = new SubClass();
        assertThat(subClass, instanceOf(BaseClass.class));
    }
}
maba
  • 47,113
  • 10
  • 108
  • 118
  • 4
    Here is the link to the Matcher being used: http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/CoreMatchers.html#instanceOf(java.lang.Class) – John B Sep 13 '12 at 11:12
  • 3
    FYI, MatcherAssert.assertThat behaves better (provides better logging in the case of errors) than Assert.assertThat. I recommend using it instead. http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/MatcherAssert.html – John B Sep 13 '12 at 11:15
  • Thanks for your answers/comments. All useful. I'll use assertThat now in my code – RNJ Sep 13 '12 at 11:15
  • 13
    That's a trivial assertion and would be a compile error if not true in the example! Usually you want to go down the class hierarchy with `instanceof`: `BaseClass subClass = new SubClass(); assertThat(subClass, isA(SubClass.class));`, but it doesn't compile because `SubClass` is not `? super BaseClass`. – TWiStErRob Sep 03 '14 at 10:01
  • 3
    @TWiStErRob I don't understand what you are trying to say here... Try to change the `instanceOf(BaseClass.class)` to `instanceOf(String.class)` and you'll see that it compile just fine but there will be an AssertionError thrown. – maba Sep 03 '14 at 11:39
  • 1
    @maba, he's talking about isA for some reason, which captures the class, it accepts `Class` instead of `Class>` (which is what instanceOf does). Since it captures the class, it would be a compile time error to do isA with a class incompatible to the instance. https://github.com/hamcrest/JavaHamcrest/issues/39 – Vsevolod Golovanov Jun 28 '17 at 08:45
  • `AssertThat` is now deprecated in newer jUnit – Carmageddon Nov 27 '17 at 15:46
  • @Carmageddon Simply use the `assertThat` in Hamcrest which is not deprecated. – Franklin Yu Jul 11 '19 at 16:13
  • @FranklinYu Its been a year and half, thanks. I don't remember the situation anymore, I think I did not have the extra library available to me at that time... thanks though! – Carmageddon Jul 13 '19 at 02:23
79

Since assertThat which was the old answer is now deprecated, I am posting the correct solution:

assertTrue(objectUnderTest instanceof TargetObject);

Carmageddon
  • 2,627
  • 4
  • 36
  • 56
  • 2
    if objectUnderTest is a subclass of TargetObject, this will still result into `true` right? And I think you want to test the actual type. – EricG Nov 27 '18 at 10:33
  • 1
    I feel this is NOT the correct answer. The original question was asking for something that specifically checks on the exact type of the object. This solutions does not that (as mentioned by @EircG above) and it has even been provided by the user originally asking the question, so definitely not the "correct" answer imo. For the correct answer, please check the Franklin Yu answer. – kekko12 Sep 08 '19 at 15:44
  • Well, it has the downside which @EricG mentioned yes, about Franklin's answer - I just looked at it, and it didnt make sense to me so I just tested in my project with Junit5 - it is wrong!! there is no such syntax for instanceof , nor a method called InstanceOf! He is totally wrong. I stand by my answer still, and as evidenced, it was helpful to at least 30 people who upvoted it! (I assume you downvoted). – Carmageddon Sep 09 '19 at 19:01
  • @kekko12 My answer doesn’t check the exact type either; it accepts subclass similar to this answer. I have updated my answer to address it; sorry that I didn’t notice this part in question. I think exact equality isn’t included in most assertion library because it isn’t frequently used. – Franklin Yu Sep 10 '19 at 01:22
  • @Carmageddon The answer from Franlin Yu does work fine *if* you use hamcrest assertion importing: ``` import static org.hamcrest.CoreMatchers.instanceOf; ``` ss per his code samples. I do admit though I overlooked at Franklin answer and in fact, these 2 answers are functionally equivalent, so I guess it is just a matter of preference in the end. – kekko12 Sep 13 '19 at 13:07
39

Solution for JUnit 5

The documentation says:

However, JUnit Jupiter’s org.junit.jupiter.Assertions class does not provide an assertThat() method like the one found in JUnit 4’s org.junit.Assert class which accepts a Hamcrest Matcher. Instead, developers are encouraged to use the built-in support for matchers provided by third-party assertion libraries.

Example for Hamcrest:

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.jupiter.api.Test;

class HamcrestAssertionDemo {

    @Test
    void assertWithHamcrestMatcher() {
        SubClass subClass = new SubClass();
        assertThat(subClass, instanceOf(BaseClass.class));
    }

}

Example for AssertJ:

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

class AssertJDemo {

    @Test
    void assertWithAssertJ() {
        SubClass subClass = new SubClass();
        assertThat(subClass).isInstanceOf(BaseClass.class);
    }

}

Note that this assumes you want to test behaviors similar to instanceof (which accepts subclasses). If you want exact equal type, I don’t see a better way than asserting the two class to be equal like you mentioned in the question.

Franklin Yu
  • 8,920
  • 6
  • 43
  • 57
  • 1
    In a sense, the original `assertThat()` is deferred to Hamcrest, so that JUnit also works with third-party assertion libraries. – Franklin Yu Jan 10 '18 at 16:21
  • I just tested this answer, it is NOT correct and leads to multiple compilation errors: Illegal start of expression, illegal start of type, ';' expected... In other words, your second parameter to the assertThat matcher, CANNOT be "instanceof (BaseClass.class)"! In fact, you didnt even type that correctly, the syntax you used is slightly different - "InstanceOf(" - as a function call! There is no such function actually... was it even tested by anyone? It seems to have been manually typed without any tests – Carmageddon Sep 09 '19 at 19:00
  • @Carmageddon I provided two answers, one for Hamcrest and the other for AssertJ. Which one are you talking about? – Franklin Yu Sep 10 '19 at 01:03
  • @Carmageddon I suspect that you are talking about the Hamcrest example and you miss-typed `instanceOf` as `instanceof` (mind the case). `instanceOf` is [a function](http://hamcrest.org/JavaHamcrest/javadoc/2.1/org/hamcrest/CoreMatchers.html#instanceOf-java.lang.Class-) while `instanceof` is [a Java keyword](https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.20.2). – Franklin Yu Sep 10 '19 at 01:14
  • I referred to the Hamcrest one of course, and I tried both keyword AND as a function after I noticed thats how you wrote it - there is no such function... – Carmageddon Sep 11 '19 at 02:57
  • @Carmageddon From my comment above I have already linked to the Javadoc of this function so it clearly exist. If your compiler cannot find the function then there is something wrong with your environment. For example, please check whether you have the class file or Jar file in classpath, and you are using the correct version. Or maybe you missed the import statements? What error you got? – Franklin Yu Sep 11 '19 at 15:33
  • Hm I assume that the recent downvote isn't casted by this user since it has been a few weeks. Would be more helpful if the downvoter I receive a comment about it. – Franklin Yu Oct 02 '19 at 04:53
  • use `assertThat(actualException, not(instanceOf(BaseClass.class))); ` for negative test. – Shrikant Prabhu Jul 13 '21 at 18:07
9

Experimental Solution for JUnit 5.8

In Junit 5.8, the experimental assertInstanceOf() method was added, so you don't need Hamcrest or AssertJ anymore. The solution is now as simple as:

import static org.junit.jupiter.api.Assertions.assertInstanceOf;

import org.junit.Test;

public class InstanceOfTest {

    @Test
    public void testInstanceOf() {
        SubClass subClass = new SubClass();
        assertInstanceOf(BaseClass.class, subClass);
    }
}

gla3dr
  • 2,179
  • 16
  • 29
6

Solution for JUnit 5 for Kotlin!

Example for Hamcrest:

import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
import org.junit.jupiter.api.Test

class HamcrestAssertionDemo {

    @Test
    fun assertWithHamcrestMatcher() {
        val subClass = SubClass()
        MatcherAssert.assertThat(subClass, CoreMatchers.instanceOf<Any>(BaseClass::class.java))
    }

}

Example for AssertJ:

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

class AssertJDemo {

    @Test
    fun assertWithAssertJ() {
        val subClass = SubClass()
        assertThat(subClass).isInstanceOf(BaseClass::class.java)
    }

}
Naruto Sempai
  • 6,233
  • 8
  • 35
  • 51
6

Solution for JUnit for Kotlin

What worked for me:

assert(obj is ClassName)

for exmaple

assert(obj is User)

NOTE: assert is coming from AssertionsJVM.kt file

Mahmoud Mabrok
  • 1,362
  • 16
  • 24