Potwierdź, że obiekt jest określonym typem

195

Czy w JUnit można stwierdzić, że obiekt jest instancją klasy? Z różnych powodów w teście mam obiekt, który chcę sprawdzić typ. Czy jest to typ Object1 czy typ Object2?

Obecnie mam:

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

To działa, ale zastanawiałem się, czy istnieje bardziej ekspresyjny sposób na zrobienie tego.

Na przykład coś takiego:

assertObjectIsClass(myObject, Object1);

Mógłbym to zrobić:

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

Czy istnieje konkretna metoda asercji, która pozwala mi testować typ obiektu w bardziej elegancki, płynny sposób?

RNJ
źródło
15
Czy zdajesz sobie z tego sprawę assertTrue(myObject instanceof Object1);i assertEquals(myObject.class, Object1.getClass());czy faktycznie są to różne testy? Pierwszy akceptuje myObject jako instancję podklasy Object1, później nie.
Erich Kitzmueller,
@ammoQ Bardzo dobry punkt. Nie myślałem o podklasach. Dzięki za wyjaśnienie
RNJ,
1
jak wskazuje maba, rozważ użycie Hamcrest. To więcej niż tylko to, że masz lepszy test działania. Hamcrest zapewnia również znacznie lepsze rejestrowanie awarii niż standardowe assertTrue. assertTruepowiedziałby po prostu expected true got false, Hamcrest powiedziałbyexpected instanced of XYZ, got instance of ABC
Jan B

Odpowiedzi:

253

Możesz użyć assertThatmetody i dopasowań dostarczonych z JUnit.

Spójrz na ten link, który opisuje trochę o JUnit Matchers.

Przykład:

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
źródło
4
Oto link do używanego Matchera
John B
3
Do Twojej wiadomości MatcherAssert.assertThat zachowuje się lepiej (zapewnia lepsze rejestrowanie w przypadku błędów) niż Assert.assertThat. Polecam zamiast tego go używać. hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/…
John B
13
To trywialne stwierdzenie i byłby to błąd kompilacji, jeśli nie byłby prawdziwy w przykładzie! Zwykle chcesz iść w dół hierarchii klasowej z instanceof: BaseClass subClass = new SubClass(); assertThat(subClass, isA(SubClass.class));, ale nie skompilować, ponieważ SubClassnie jest ? super BaseClass.
TWiStErRob
3
@TWiStErRob Nie rozumiem co próbujesz tu powiedzieć ... Spróbuj zmienić instanceOf(BaseClass.class)się instanceOf(String.class), a zobaczysz, że to w porządku, ale po prostu skompilować nie będzie AssertionError rzucony.
maba
1
@maba, z jakiegoś powodu mówi o isA, który przechwytuje klasę, akceptuje Class<T>zamiast niej Class<?>(co robi instancjaOf). Ponieważ przechwytuje klasę, błędem czasu kompilacji byłoby isA z klasą niezgodną z instancją. github.com/hamcrest/JavaHamcrest/issues/39
Vsevolod Golovanov
47

Ponieważ assertThatpoprzednia odpowiedź jest obecnie nieaktualna, zamieszczam prawidłowe rozwiązanie:

assertTrue(objectUnderTest instanceof TargetObject);

Carmageddon
źródło
2
jeśli objectUnderTest jest podklasą TargetObject, nadal będzie to oznaczać, że truetak? I myślę, że chcesz przetestować rzeczywisty typ.
EricG
Wydaje mi się, że NIE jest to poprawna odpowiedź. Pierwotne pytanie dotyczyło czegoś, co dokładnie sprawdza dokładny typ obiektu. Takie rozwiązania nie zapewniają (jak wspomniano powyżej @EircG), a nawet zostały dostarczone przez użytkownika, który pierwotnie zadał pytanie, więc zdecydowanie nie jest to „poprawna” odpowiedź imo. Aby uzyskać poprawną odpowiedź, sprawdź odpowiedź Franklin Yu.
kekko12
Cóż, ma to wadę, o której wspomniał @EricG, tak, w odpowiedzi Franklin - właśnie na to spojrzałem, i nie miało to dla mnie sensu, więc właśnie przetestowałem w moim projekcie z Junit5 - to źle !! nie ma takiej składni dla instanceof, ani metody o nazwie InstanceOf! On jest całkowicie w błędzie. Nadal trzymam się mojej odpowiedzi i, jak udowodniono, była pomocna co najmniej 30 osobom, które ją głosowały! (Zakładam, że nie doceniłeś).
Carmageddon,
@ kekko12 Moja odpowiedź też nie sprawdza dokładnego typu; akceptuje podklasę podobną do tej odpowiedzi. Zaktualizowałem swoją odpowiedź, aby ją rozwiązać; przepraszam, że nie zauważyłem tej części, o której mowa. Myślę, że dokładna równość nie jest zawarta w większości bibliotek asercji, ponieważ nie jest często używana.
Franklin Yu,
@Carmageddon Odpowiedź Franlina Yu działa dobrze, jeśli używasz importowania twierdzenia hamcrest: `` import static org.hamcrest.CoreMatchers.instanceOf; `` ss na jego próbki kodu. Przyznaję, chociaż przeoczyłem odpowiedź Franklina i faktycznie te 2 odpowiedzi są funkcjonalnie równoważne, więc sądzę, że w końcu jest to tylko kwestia preferencji.
kekko12
21

Rozwiązanie dla JUnit 5

Dokumentacja mówi:

Jednak org.junit.jupiter.Assertionsklasa JUnit Jupiter nie zapewnia assertThat()metody takiej jak ta znaleziona w org.junit.Assertklasie JUnit 4, która akceptuje Hamcrest Matcher. Zamiast tego programiści są zachęcani do korzystania z wbudowanej obsługi dopasowań dostarczanej przez zewnętrzne biblioteki asercji.

Przykład dla 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));
    }

}

Przykład dla 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);
    }

}

Zauważ, że zakłada to, że chcesz przetestować zachowania podobne do instanceof(które akceptują podklasy). Jeśli chcesz dokładnie równego typu, nie widzę lepszego sposobu niż twierdzenie, że dwie klasy są równe, jak wspomniano w pytaniu.

Franklin Yu
źródło
1
W pewnym sensie oryginał assertThat()jest odroczony do Hamcrest, więc JUnit działa również z bibliotekami asercji innych firm.
Franklin Yu,
Właśnie przetestowałem tę odpowiedź, NIE jest ona poprawna i prowadzi do wielu błędów kompilacji: niedozwolony początek wyrażenia, niedozwolony początek typu, ';' Oczekiwano ... Innymi słowy, drugim parametrem modułu dopasującego assertThat NIE MOŻE być „instanceof (BaseClass.class)”! W rzeczywistości nawet nie wpisałeś tego poprawnie, zastosowana składnia jest nieco inna - „InstanceOf (” - jako wywołanie funkcji! Tak naprawdę nie ma takiej funkcji ... czy w ogóle ktoś ją przetestował? Wygląda na to, że została ręcznie wpisany bez żadnych testów
Carmageddon,
@Carmageddon Podałem dwie odpowiedzi, jedną dla Hamcrest i drugą dla AssertJ. O którym mówisz?
Franklin Yu,
@Carmageddon Podejrzewam, że mówisz przykładzie Hamcrest i pominięcia wpisany instanceOfjako instanceof(przeszkadza sprawę). instanceOfjest funkcją, podczas gdy instanceofjest słowem kluczowym Java .
Franklin Yu,
Odniosłem się oczywiście do Hamcrestu i próbowałem obu słów kluczowych ORAZ jako funkcji po tym, jak zauważyłem, że tak to napisałeś - nie ma takiej funkcji ...
Carmageddon
3

Rozwiązanie dla JUnit 5 dla Kotlin!

Przykład dla 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))
    }

}

Przykład dla 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
źródło
1
Dzięki za to bardzo eleganckie rozwiązanie assertJ
Aleks Nine