欢迎来到淼淼之森的个人小站。  交流请加我微信好友: studyjava。  也欢迎关注同名公众号:Java学习之道

单元测试中如何mock用@Value注解注入的属性 置顶!

  |   0 评论   |   0 浏览

实际项目开发中,我们经常会使用@Value注解从配置文件中注入属性值,写单元测试时,在不启动容器的条件下,如何对这种属性进行mock呢?

对这种情况,Spring提供了一个很好的工具类ReflectionTestUtils来实现。

注入属性:

@Value("${option.switch}")
private String switchValue;

对这个属性,在单测中可以这样mock:

ReflectionTestUtils.setField(targetObject, "switchValue", "turn on");

顾名思义,该工具类就是利用反射机制来实现的,底层源码如图所示:

/**
	 * Set the {@linkplain Field field} with the given {@code name}/{@code type}
	 * on the provided {@code targetObject}/{@code targetClass} to the supplied
	 * {@code value}.
	 * <p>If the supplied {@code targetObject} is a <em>proxy</em>, it will
	 * be {@linkplain AopTestUtils#getUltimateTargetObject unwrapped} allowing
	 * the field to be set on the ultimate target of the proxy.
	 * <p>This method traverses the class hierarchy in search of the desired
	 * field. In addition, an attempt will be made to make non-{@code public}
	 * fields <em>accessible</em>, thus allowing one to set {@code protected},
	 * {@code private}, and <em>package-private</em> fields.
	 * @param targetObject the target object on which to set the field; may be
	 * {@code null} if the field is static
	 * @param targetClass the target class on which to set the field; may
	 * be {@code null} if the field is an instance field
	 * @param name the name of the field to set; may be {@code null} if
	 * {@code type} is specified
	 * @param value the value to set
	 * @param type the type of the field to set; may be {@code null} if
	 * {@code name} is specified
	 * @since 4.2
	 * @see ReflectionUtils#findField(Class, String, Class)
	 * @see ReflectionUtils#makeAccessible(Field)
	 * @see ReflectionUtils#setField(Field, Object, Object)
	 * @see AopTestUtils#getUltimateTargetObject(Object)
	 */
	public static void setField(Object targetObject, Class<?> targetClass, String name, Object value, Class<?> type) {
		Assert.isTrue(targetObject != null || targetClass != null,
			"Either targetObject or targetClass for the field must be specified");

		if (targetObject != null && springAopPresent) {
			targetObject = AopTestUtils.getUltimateTargetObject(targetObject);
		}
		if (targetClass == null) {
			targetClass = targetObject.getClass();
		}

		Field field = ReflectionUtils.findField(targetClass, name, type);
		if (field == null) {
			throw new IllegalArgumentException(String.format(
					"Could not find field '%s' of type [%s] on %s or target class [%s]", name, type,
					safeToString(targetObject), targetClass));
		}

		if (logger.isDebugEnabled()) {
			logger.debug(String.format(
					"Setting field '%s' of type [%s] on %s or target class [%s] to value [%s]", name, type,
					safeToString(targetObject), targetClass, value));
		}
		ReflectionUtils.makeAccessible(field);
		ReflectionUtils.setField(field, targetObject, value);
	}

	/**
	 * Attempt to find a {@link Field field} on the supplied {@link Class} with the
	 * supplied {@code name} and/or {@link Class type}. Searches all superclasses
	 * up to {@link Object}.
	 * @param clazz the class to introspect
	 * @param name the name of the field (may be {@code null} if type is specified)
	 * @param type the type of the field (may be {@code null} if name is specified)
	 * @return the corresponding Field object, or {@code null} if not found
	 */
	public static Field findField(Class<?> clazz, String name, Class<?> type) {
		Assert.notNull(clazz, "Class must not be null");
		Assert.isTrue(name != null || type != null, "Either name or type of the field must be specified");
		Class<?> searchType = clazz;
		while (Object.class != searchType && searchType != null) {
			Field[] fields = getDeclaredFields(searchType);
			for (Field field : fields) {
				if ((name == null || name.equals(field.getName())) &&
						(type == null || type.equals(field.getType()))) {
					return field;
				}
			}
			searchType = searchType.getSuperclass();
		}
		return null;
	}

具体可参见:How do I mock an autowired @Value field in Spring with Mockito? - Stack Overflow


标题:单元测试中如何mock用@Value注解注入的属性
作者:jerrycookie
地址:https://www.mmzsblog.cn/articles/2023/07/10/1688967983371.html

如未加特殊说明,文章均为原创,转载必须注明出处。均采用CC BY-SA 4.0 协议

本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。若本站转载文章遗漏了原文链接,请及时告知,我们将做删除处理!文章观点不代表本网站立场,如需处理请联系首页客服。
• 网站转载须在文章起始位置标注作者及原文连接,否则保留追究法律责任的权利。
• 公众号转载请联系网站首页的微信号申请白名单!

个人微信公众号 ↓↓↓                 

微信搜一搜 Java 学习之道