首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么测试字符串域的单元有时会使用这个通用的数据测试代码失败?

为什么测试字符串域的单元有时会使用这个通用的数据测试代码失败?
EN

Stack Overflow用户
提问于 2018-06-21 06:02:24
回答 1查看 183关注 0票数 0

我正在使用一个通用的dto测试代码来测试我的dto,它是我在https://objectpartners.com/2016/02/16/automatically-junit-test-dto-and-transfer-objects/上找到的。大多数情况下,它工作得很完美。突然有一天,我发现只有一个测试类的测试失败。它偶尔会发生,这意味着它有时会发生,大多数情况下,它工作得很好。

代码语言:javascript
复制
pubic class MyDtoClass implements Serializable {

    private String includeNullValue;

    public String getIncludeNullValue() {
        return includeNullValue;
    }

    public void setIncludeNullValue(String includeNullValue) {
        this.includeNullValue = includeNullValue;
    }
}

测试失败时会输出以下错误消息:

代码语言:javascript
复制
java.lang.AssertionError: includeNullValue is different expected same:<> was not:<null>
Expected :
Actual   :null

我的测试类如下

代码语言:javascript
复制
public class MyDtoClassTest extends DtoTest<MyDtoClass> {

    private static MyDtoClass myDtoClass;

    @Before
    public void setup() {
        myDtoClass = new MyDtoClass();
    }

    @Override
    protected MyDtoClass getInstance() {
        return myDtoClass;
    }
}

有什么线索吗?提前谢谢。

更新:按照建议,我直接在这里发布DtoTest.java,如下所示

代码语言:javascript
复制
public abstract class DtoTest<T> {

    /** A map of default mappers for common objects. */
    private static final ImmutableMap<Class<?>, Supplier<?>> DEFAULT_MAPPERS;

    static {
        final Builder<Class<?>, Supplier<?>> mapperBuilder = ImmutableMap.builder();

        /* Primitives */
        mapperBuilder.put(int.class, () -> 0);
        mapperBuilder.put(double.class, () -> 0.0d);
        mapperBuilder.put(float.class, () -> 0.0f);
        mapperBuilder.put(long.class, () -> 0l);
        mapperBuilder.put(boolean.class, () -> true);
        mapperBuilder.put(short.class, () -> (short) 0);
        mapperBuilder.put(byte.class, () -> (byte) 0);
        mapperBuilder.put(char.class, () -> (char) 0);

        mapperBuilder.put(Integer.class, () -> Integer.valueOf(0));
        mapperBuilder.put(Double.class, () -> Double.valueOf(0.0));
        mapperBuilder.put(Float.class, () -> Float.valueOf(0.0f));
        mapperBuilder.put(Long.class, () -> Long.valueOf(0));
        mapperBuilder.put(Boolean.class, () -> Boolean.TRUE);
        mapperBuilder.put(Short.class, () -> Short.valueOf((short) 0));
        mapperBuilder.put(Byte.class, () -> Byte.valueOf((byte) 0));
        mapperBuilder.put(Character.class, () -> Character.valueOf((char) 0));

        mapperBuilder.put(BigDecimal.class, () -> BigDecimal.ONE);
        mapperBuilder.put(Date.class, () -> new Date());

        /* Collection Types. */
        mapperBuilder.put(Set.class, () -> Collections.emptySet());
        mapperBuilder.put(SortedSet.class, () -> Collections.emptySortedSet());
        mapperBuilder.put(List.class, () -> Collections.emptyList());
        mapperBuilder.put(Map.class, () -> Collections.emptyMap());
        mapperBuilder.put(SortedMap.class, () -> Collections.emptySortedMap());

        DEFAULT_MAPPERS = mapperBuilder.build();
    }

    /** The get fields to ignore and not try to test. */
    private final Set<String> ignoredGetFields;

    /**
     * A custom mapper. Normally used when the test class has abstract objects.
     */
    private final ImmutableMap<Class<?>, Supplier<?>> mappers;

    /**
     * Creates an instance of {@link DtoTest} with the default ignore fields.
     */
    protected DtoTest() {
        this(null, null);
    }

    /**
     * Creates an instance of {@link DtoTest} with ignore fields and additional custom mappers.
     *
     * @param customMappers Any custom mappers for a given class type.
     * @param ignoreFields The getters which should be ignored (e.g., "getId" or "isActive").
     */
    protected DtoTest(Map<Class<?>, Supplier<?>> customMappers, Set<String> ignoreFields) {
        this.ignoredGetFields = new HashSet<>();
        if (ignoreFields != null) {
            this.ignoredGetFields.addAll(ignoreFields);
        }
        this.ignoredGetFields.add("getClass");

        if (customMappers == null) {
            this.mappers = DEFAULT_MAPPERS;
        } else {
            final Builder<Class<?>, Supplier<?>> builder = ImmutableMap.builder();
            builder.putAll(customMappers);
            builder.putAll(DEFAULT_MAPPERS);
            this.mappers = builder.build();
        }
    }

    /**
     * Calls a getter and verifies the result is what is expected.
     *
     * @param fieldName The field name (used for error messages).
     * @param getter The get {@link Method}.
     * @param instance The test instance.
     * @param expected The expected result.
     *
     * @throws IllegalAccessException if this Method object is enforcing Java language access control and the underlying
     *             method is inaccessible.
     * @throws IllegalArgumentException if the method is an instance method and the specified object argument is not an
     *             instance of the class or interface declaring the underlying method (or of a subclass or implementor
     *             thereof); if the number of actual and formal parameters differ; if an unwrapping conversion for
     *             primitive arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to
     *             the corresponding formal parameter type by a method invocation conversion.
     * @throws InvocationTargetException if the underlying method throws an exception.
     */
    private void callGetter(String fieldName, Method getter, T instance, Object expected)
            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        final Object getResult = getter.invoke(instance);

        if (getter.getReturnType().isPrimitive()) {
            /* Calling assetEquals() here due to autoboxing of primitive to object type. */
            assertEquals(fieldName + " is different", expected, getResult);
        } else {
            /* This is a normal object. The object passed in should be the exactly same object we get back. */
            assertSame(fieldName + " is different", expected, getResult);
        }
    }

    /**
     * Creates an object for the given {@link Class}.
     *
     * @param fieldName The name of the field.
     * @param clazz The {@link Class} type to create.
     *
     * @return A new instance for the given {@link Class}.
     *
     * @throws InstantiationException If this Class represents an abstract class, an interface, an array class, a
     *             primitive type, or void; or if the class has no nullary constructor; or if the instantiation fails
     *             for some other reason.
     * @throws IllegalAccessException If the class or its nullary constructor is not accessible.
     *
     */
    private Object createObject(String fieldName, Class<?> clazz)
            throws InstantiationException, IllegalAccessException {

      try {      
          final Supplier<?> supplier = this.mappers.get(clazz);
          if (supplier != null) {
              return supplier.get();
          }

          if (clazz.isEnum()) {
              return clazz.getEnumConstants()[0];
          }

          return clazz.newInstance();        
        } catch (IllegalAccessException | InstantiationException e) {
            throw new RuntimeException("Unable to create objects for field '" + fieldName + "'.", e);
        }
    }

    /**
     * Returns an instance to use to test the get and set methods.
     *
     * @return An instance to use to test the get and set methods.
     */
    protected abstract T getInstance();

    /**
     * Tests all the getters and setters. Verifies that when a set method is called, that the get method returns the
     * same thing. This will also use reflection to set the field if no setter exists (mainly used for user immutable
     * entities but Hibernate normally populates).
     *
     * @throws Exception If an expected error occurs.
     */
    @Test
    public void testGettersAndSetters() throws Exception {
        /* Sort items for consistent test runs. */
        final SortedMap<String, GetterSetterPair> getterSetterMapping = new TreeMap<>();

        final T instance = getInstance();

        for (final Method method : instance.getClass().getMethods()) {
            final String methodName = method.getName();

            if (this.ignoredGetFields.contains(methodName)) {
                continue;
            }

            String objectName;
            if (methodName.startsWith("get") && method.getParameters().length == 0) {
                /* Found the get method. */
                objectName = methodName.substring("get".length());

                GetterSetterPair getterSettingPair = getterSetterMapping.get(objectName);
                if (getterSettingPair == null) {
                    getterSettingPair = new GetterSetterPair();
                    getterSetterMapping.put(objectName, getterSettingPair);
                }
                getterSettingPair.setGetter(method);
            } else if (methodName.startsWith("set") && method.getParameters().length == 1) {
                /* Found the set method. */
                objectName = methodName.substring("set".length());

                GetterSetterPair getterSettingPair = getterSetterMapping.get(objectName);
                if (getterSettingPair == null) {
                    getterSettingPair = new GetterSetterPair();
                    getterSetterMapping.put(objectName, getterSettingPair);
                }
                getterSettingPair.setSetter(method);
            } else if (methodName.startsWith("is") && method.getParameters().length == 0) {
                /* Found the is method, which really is a get method. */
                objectName = methodName.substring("is".length());

                GetterSetterPair getterSettingPair = getterSetterMapping.get(objectName);
                if (getterSettingPair == null) {
                    getterSettingPair = new GetterSetterPair();
                    getterSetterMapping.put(objectName, getterSettingPair);
                }
                getterSettingPair.setGetter(method);
            }
        }

        /*
         * Found all our mappings. Now call the getter and setter or set the field via reflection and call the getting
         * it doesn't have a setter.
         */
        for (final Entry<String, GetterSetterPair> entry : getterSetterMapping.entrySet()) {
            final GetterSetterPair pair = entry.getValue();

            final String objectName = entry.getKey();
            final String fieldName = objectName.substring(0, 1).toLowerCase() + objectName.substring(1);

            if (pair.hasGetterAndSetter()) {
                /* Create an object. */
                final Class<?> parameterType = pair.getSetter().getParameterTypes()[0];
                final Object newObject = createObject(fieldName, parameterType);

                pair.getSetter().invoke(instance, newObject);

                callGetter(fieldName, pair.getGetter(), instance, newObject);
            } else if (pair.getGetter() != null) {
                /*
                 * Object is immutable (no setter but Hibernate or something else sets it via reflection). Use
                 * reflection to set object and verify that same object is returned when calling the getter.
                 */
                final Object newObject = createObject(fieldName, pair.getGetter().getReturnType());
                final Field field = instance.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                field.set(instance, newObject);

                callGetter(fieldName, pair.getGetter(), instance, newObject);
            }
        }
    }
}
EN

回答 1

Stack Overflow用户

发布于 2018-06-21 07:35:57

IMHO在设置方法上使用anotation @Before有问题

使用@

注释公共空方法会导致该方法在测试方法之前运行

但是在您的代码中,您没有任何@Test方法,因此对象myDtoClass可能不会在测试前初始化。

将代码更改为

代码语言:javascript
复制
public class MyDtoClassTest extends DtoTest<MyDtoClass> {

    @Override
    protected MyDtoClass getInstance() {
       return new MyDtoClass();
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50957696

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档