【问题标题】:How do I match a Class<?> against a specific Class instance in a Hamcrest Matcher?如何将 Class<?> 与 Hamcrest Matcher 中的特定 Class 实例进行匹配?
【发布时间】:2014-06-07 02:15:12
【问题描述】:

我希望能够断言注释值与预期的类匹配:

import org.junit.Test;

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

public final class AnnotatedClassTest {
    @Test
    public void someAnnotationIsString() {
        assertThat(
            AnnotatedClass.class.getAnnotation(SomeAnnotation.class).value(),
            is(equalTo(String.class));
    }
}

但是,这是一个类型错误:

AnnotatedClassTest.java:9: error: no suitable method found for assertThat(Class<CAP#1>,Matcher<Class<String>>)
        assertThat(
        ^
    method MatcherAssert.<T#1>assertThat(T#1,Matcher<? super T#1>) is not applicable
      (actual argument Matcher<Class<String>> cannot be converted to Matcher<? super Class<CAP#1>> by method invocation conversion)
    method MatcherAssert.<T#2>assertThat(String,T#2,Matcher<? super T#2>) is not applicable
      (cannot instantiate from arguments because actual and formal argument lists differ in length)
    method MatcherAssert.assertThat(String,boolean) is not applicable
      (actual argument Class<CAP#1> cannot be converted to String by method invocation conversion)
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in method <T#1>assertThat(T#1,Matcher<? super T#1>)
    T#2 extends Object declared in method <T#2>assertThat(String,T#2,Matcher<? super T#2>)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 error

这里是注解类:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface SomeAnnotation {
    Class<?> value();
}

以及我应用该注释的类:

@SomeAnnotation(String.class)
public final class AnnotatedClass {
}

出现类型错误是因为:

Class<?> value = AnnotatedClass.class.getAnnotation(SomeAnnotation.class).value();

还有:

Matcher<Class<String>> classMatcher = is(equalTo(String.class));

无法满足我打算定位的签名:

<T> void assertThat(T, Matcher<? super T>)

通过基于第一个参数修复 T 更具体的是:

void assertThat(Class<?>, Matcher<? super Class<?>>)

我喜欢 assertThat 的统一性,并希望避免使用 assertEquals

这里是如何使用 assertEquals (特别是没有回答我的问题):

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public final class AnnotatedClassTest {
    @Test
    public void someAnnotationIsString() {
        assertEquals(
            String.class,
            AnnotatedClass.class.getAnnotation(SomeAnnotation.class).value());
    }
}

如何将 Class&lt;?&gt; 与 Hamcrest 匹配器中的特定类实例进行匹配?

如果你能提供一个令人信服的解释,说明这是不可能的就是一个可以接受的答案。

【问题讨论】:

  • 写得很好的问题。
  • 当我在这里得到很好的答案时,这是值得的。通常对未来的旅行者也很方便:)

标签: java generics junit junit4 hamcrest


【解决方案1】:

一种相当丑陋的方法是使用原始类型。

// this declaration is RAW
Class expected = String.class;
assertThat(AnnotatedClass.class.getAnnotation(SomeAnnotation.class)
                .value(), is(equalTo(expected)));

但一种更好的方法是为equalTo(..)的调用指定一个泛型类型参数。

Class<?> expected = String.class;
assertThat(AnnotatedClass.class.getAnnotation(SomeAnnotation.class)
        .value(), is(CoreMatchers.<Class<?>>equalTo(expected)));

(您不需要将String.class 提取到变量中。)

【讨论】:

  • assertThat(AnnotatedClass.class.getAnnotation(SomeAnnotation.class).value(), is(equalTo((Class) String.class)));也很好用。谢谢你:)
  • 我知道有一个逃生舱,但我忘记了原始类型。我也喜欢类型见证解决方案。对于测试,为了简洁起见,我会使用原始数据,但为了更好的安全性,我会使用见证数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-05
  • 1970-01-01
  • 2019-01-12
  • 2011-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多