(4.5.5.4)Espresso的进阶: OnView & onData & Matchers

本文深入剖析了Espresso UI测试框架中的核心概念和技术细节,包括Matcher的实现方式、工具集的功能特性、AdapterView及RecyclerView的交互操作等。通过具体实例展示了如何定位界面元素并执行相应操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Espresso编写自动化就做三件事情:找某些东西、做某些事情、检查某些东西

  • 找到 并返回 XXInteraction交互类
    • public static ViewInteraction onView(final Matcher< View > viewMatcher)
    • public static DataInteraction onData(Matcher< ? extends Object> dataMatcher)

让我们先来看看Matchers 都有哪些API可供我们使用

  • Classes:BoundedMatcher< T, S extends T >
Some matcher sugar that lets you create a matcher for a given type but only process items of a specific subtype of that matcher.
  • Classes:CursorMatchers
A collection of Hamcrest matchers that matches a data row in a Cursor.
  • Classes:CursorMatchers.CursorMatcher
A Matcher that matches Cursors based on values in their columns.
  • Classes:LayoutMatchers
A collection of hamcrest matches to detect typical layout issues.
  • Classes:PreferenceMatchers
A collection of hamcrest matchers that match Preferences.
  • Classes:RootMatchers
A collection of matchers for Root objects.
  • Classes:ViewMatchers
A collection of hamcrest matchers that match Views.
  • Enums:ViewMatchers.Visibility
ViewMatchers.Visibility Enumerates the possible list of values for View.getVisibility()

一、源码分析

  • 所有的校验都 实现了 interface Matcher

public interface Matcher extends SelfDescribing {

    /**
     * 遍历当前视图中的Views,匹配到则返回true
     */
    boolean matches(Object item);

    /**
    * 描述信息
    */
    void describeMismatch(Object item, Description mismatchDescription);
}

当然在实际过程中,我们没有直接去实现Matcher,而是实现其子类BaseMatcher所派生的封装类。

public abstract class BaseMatcher<T> implements Matcher<T>

譬如:

//进行类型校验
abstract class TypeSafeMatcher<T> extends BaseMatcher<T>

1.1 TypeSafeMatcher

直接上两个例子吧:

/**
* 返回具有指定 Tag 的View
*/
 public static Matcher<View> withTag(final Object tag) {
        return new TypeSafeMatcher<View>() {
            @Override
            public void describeTo(Description description) {
                description.appendText("with key: " + tag);
            }

            @Override
            public boolean matchesSafely(View view) {
                return tag.equals(view.getTag());
            }
        };
    }
     /**
     * 在X中的 满足Y 的 X的直系子节点
     * @param parentMatcher 目标view的直接父节点
     * @param childtMatcher 目标view满足
     * @return
     */
    public static Matcher<View> childWithMatcher(
            final Matcher<View> parentMatcher, final Matcher<View> childtMatcher) {

        return new TypeSafeMatcher<View>() {
            @Override
            public void describeTo(Description description) {
                description.appendText("Child with childtMatcher in parent ");
                parentMatcher.describeTo(description);
            }

            @Override
            public boolean matchesSafely(View view) {
                ViewParent parent = view.getParent();
                return parent instanceof ViewGroup && parentMatcher.matches(parent)
                        && childtMatcher.matches(view);
            }
        };
    }

1.2 BoundedMatcher

相对于 TypeSafeMatcher,BoundedMatcher 允许您为给定类型创建匹配器,但只能处理该匹配器的特定子类型项;
从而不需要关注类型项,而只关注 对象的具体业务

  public static Matcher<View> withText(final Matcher<String> stringMatcher) {
    checkNotNull(stringMatcher);
    return new BoundedMatcher<View, TextView>(TextView.class) {
      @Override
      public void describeTo(Description description) {
        description.appendText("with text: ");
        stringMatcher.describeTo(description);
      }

      @Override
      public boolean matchesSafely(TextView textView) {
        return stringMatcher.matches(textView.getText().toString());
      }
    };
  }
  • BoundedMatcher来确保匹配器只匹配TextView类及其子类
  • 这使得很容易在BoundedMatcher.matchesSafely()中实现匹配逻辑本身:只需从TextView中获取getText()方法并将其送入下一个匹配器
  • 有一个简单的describeTo()方法的实现,它只用于生成调试输出到控制台。

二、工具集

2.1 ViewMatchers View匹配器适配类

最重要也是应用最广的匹配器,通过一个或者多个来定位层级里面的控件。
包含了大量的常见的匹配操作,大部分都是通过TypeSafeMatcher 和 BoundedMatcher实现的..

返回值函数示意matchesSafely原文
static voidassertThat(String message, T actual, Matcher matcher)A replacement for MatcherAssert.assertThat that renders View objects nicely.
static voidassertThat(T actual, Matcher matcher)A replacement for MatcherAssert.assertThat that renders View objects nicely.
static MatcherhasContentDescription()获取具有ContentDescription的viewview.getContentDescription() != nullReturns an Matcher that matches Views with any content description.
static MatcherhasDescendant(Matcher descendantMatcher)获取具有“descendantMatcher满足的View”作为直接或间接子节点的VIewReturns a matcher that matches Views based on the presence of a descendant in its view hierarchy.
static MatcherhasErrorText(String expectedError)获取是 EditText 及其子类类型的,并且getError()== expectedError 的ViewhasErrorText(is(expectedError))Returns a matcher that matches EditText based on edit text error string value.
static MatcherhasErrorText(Matcher stringMatcher)获取是 EditText 及其子类类型的,并且getError()满足stringMatcher的ViewstringMatcher.matches(view.getError().toString())Returns a matcher that matches EditText based on edit text error string value.
static MatcherhasFocus()获取持有焦点的Viewview.hasFocus()Returns a matcher that matches Views currently have focus.
static MatcherhasImeAction(int imeAction)支持输入的,并且具有指定imeAction的ViewReturns a matcher that matches views that support input methods (e.g. EditText) and have the* specified IME action set in its {@link EditorInfo}
static MatcherhasImeAction(Matcher imeActionMatcher)支持输入的,并且满足imeActionMatcher的ViewReturns a matcher that matches views that support input methods (e.g…
static MatcherhasLinks()获取是TextView及其子类类型的,并且具有出超链接的ViewtextView.getUrls().length > 0Returns a matcher that matches TextViews that have links.
static MatcherhasSibling(Matcher siblingMatcher)获取 在View层级上具有“满足siblingMatcher”作为直接或间接兄弟的ViewsiblingMatcher.matches(parentGroup.getChildAt(i))Returns an Matcher that matches Views based on their siblings.
static MatcherisAssignableFrom(Class clazz)获取 是clazz子类的Viewclazz.isAssignableFrom(view.getClass())Returns a matcher that matches Views which are an instance of or subclass of the provided class.
static MatcherisChecked()获取实现了Checkable接口的,并且被选中的ViewwithCheckBoxState(is(true))Returns a matcher that accepts if and only if the view is a CompoundButton (or subtype of) and is in checked state.
static MatcherisClickable()获取可以点击的Viewview.isClickable()Returns a matcher that matches Views that are clickable.
static MatcherisCompletelyDisplayed()获取正在完全显示的VIew,不包括部分显示isDisplayingAtLeast(100)Returns a matcher which only accepts a view whose height and width fit perfectly within the currently displayed region of this view.
static MatcherisDescendantOfA(Matcher ancestorMatcher)获取 拥有”满足ancestorMatcher的view”的作为父辈节点的ViewcheckAncestors(ViewParent viewParent, Matcher ancestorMatcher)Returns a matcher that matches Views based on the given ancestor type.
static MatcherisDisplayed()获取正在显示的VIew,包括部分显示view.getGlobalVisibleRect(new Rect())&& withEffectiveVisibility(Visibility.VISIBLE).matches(view)Returns a matcher that matches Views that are currently displayed on the screen to the user.
static MatcherisDisplayingAtLeast(int areaPercentage)获取至少有areaPercentage百分比在显示的ViewReturns a matcher which accepts a view so long as a given percentage of that view’s area is not obscured by any other view and is thus visible to the user.
static MatcherisEnabled()获取 isenabled的Viewview.isEnabled()Returns a matcher that matches Views that are enabled.
static MatcherisFocusable()获取可以获得焦点的Viewview.isFocusable()Returns a matcher that matches Views that are focusable.
static MatcherisJavascriptEnabled()获取是WebView及其子类的,并且开启js的ViewwebView.getSettings().getJavaScriptEnabled()Returns a matcher that matches WebView if they are evaluating Javascript.
static MatcherisNotChecked()获取实现了Checkable接口的,并且为被选中的ViewwithCheckBoxState(is(false))Returns a matcher that accepts if and only if the view is a CompoundButton (or subtype of) and is not in checked state.
static MatcherisRoot()获取是根视图的VIewview.getRootView().equals(view)Returns a matcher that matches root View.
static MatcherisSelected()获取被选中的VIewview.isSelected()Returns a matcher that matches Views that are selected.
static MatchersupportsInputMethods()获取支持输入的Viewview.onCreateInputConnection(new EditorInfo()) != nullReturns a matcher that matches views that support input methods.
static MatcherwithChild(Matcher childMatcher)获取具有 “满足childMatcher”作为直接子节点的View…childMatcher.matches(group.getChildAt(i))A matcher that returns true if and only if the view’s child is accepted by the provided matcher.
static MatcherwithClassName(Matcher classNameMatcher)获取具有 满足classNameMatcher的ClassName的ViewclassNameMatcher.matches(view.getClass().getName())Returns a matcher that matches Views with class name matching the given matcher.
static MatcherwithContentDescription(int resourceId)获取其getContentDescription的文本 == resourceId对应的文本的ViewReturns a Matcher that matches Views based on content description property value.
static MatcherwithContentDescription(String text)获取其getContentDescription的文本 == text的ViewwithContentDescription(is(text))Returns an Matcher that matches Views based on content description property value.
static MatcherwithContentDescription(Matcher charSequenceMatcher)获取其getContentDescription的文本 满足charSequenceMatcher 的ViewcharSequenceMatcher.matches(view.getContentDescription())Returns an Matcher that matches Views based on content description property value.
static MatcherwithEffectiveVisibility(ViewMatchers.Visibility visibility)获取显示在屏幕上的View,也就是其自身和其所有祖父节点都是Visible的Returns a matcher that matches Views that have “effective” visibility set to the given value.
static MatcherwithHint(Matcher stringMatcher)获取是TextView及其子类类型的,并且其getHint()的文本满足stringMatcher的ViewstringMatcher.matches(textView.getHint())Returns a matcher that matches TextViews based on hint property value.
static MatcherwithHint(int resourceId)获取是TextView及其子类类型的,并且其getText()的文本 == resourceId对应的文本的ViewwithCharSequence(resourceId, TextViewMethod.GET_HINT)Returns a matcher that matches a descendant of TextView that is displaying the hint associated with the given resource id.
static MatcherwithHint(String hintText)获取是TextView及其子类类型的,并且其getHint()的文本 == text的ViewwithHint(is(text)Returns a matcher that matches TextView based on it’s hint property value.
static MatcherwithId(Matcher integerMatcher)获取“满足integerMatcher指定的id规则”的ViewintegerMatcher.matches(view.getId())Returns a matcher that matches Views based on resource ids.
static MatcherwithId(int id)获取指定id的view,与withId(is(int))相同,但是尝试寻找对应资源(R.id.xx),如果找到则打印出with id:R.id.xx,如果找不到对应的则打印数字或未找到resources = view.getResources();return id == view.getId(Same as withId(is(int)), but attempts to look up resource name of the given id and use an R.id.myView style description with describeTo.
static MatcherwithInputType(int inputType)获取 是EditText及其子类,并且具有指定输入键盘类型的Viewview.getInputType() == inputTypeReturns a matcher that matches InputType.
static MatcherwithParent(Matcher parentMatcher)获取 具有“满足parentMatcher”的作为直接父节点的ViewparentMatcher.matches(view.getParent())A matcher that accepts a view if and only if the view’s parent is accepted by the provided matcher.
static MatcherwithResourceName(String name)获取具有指定资源名的ViewwithResourceName(is(name)Returns a matcher that matches Views based on resource id names, (for instance, channel_avatar).
static MatcherwithResourceName(Matcher stringMatcher)获取资源名满足stringMatcher的ViewstringMatcher.matches(view.getResources().getResourceEntryName(view.getId()))Returns a matcher that matches Views based on resource id names, (for instance, channel_avatar).
static MatcherwithSpinnerText(int resourceId)获取是Spinner及其子类类型的,并且其getSelectedItem()的文本 == resourceId对应的文本的ViewReturns a matcher that matches a descendant of Spinner that is displaying the string of the selected item associated with the given resource id.
static MatcherwithSpinnerText(String text)获取是Spinner及其子类类型的,并且其getSelectedItem()的文本 == text的ViewwithSpinnerText(is(text)Returns a matcher that matches Spinner based on it’s selected item’s toString value.
static MatcherwithSpinnerText(Matcher stringMatcher)获取是Spinner及其子类类型的,并且其getSelectedItem()的文本满足stringMatcher的ViewstringMatcher.matches(spinner.getSelectedItem().toString())
static MatcherwithTagKey(int key)获取 具有指定名称的tag的ViewwithTagKey(key, Matchers.notNullValue())Returns a matcher that matches View based on tag keys.
static MatcherwithTagKey(int key, Matcher objectMatcher)获取 指定名称的tag满足objectMatcher 的ViewobjectMatcher.matches(view.getTag(key)Returns a matcher that matches Views based on tag keys.
static MatcherwithTagValue(Matcher tagValueMatcher)获取 其tag满足objectMatcher 的ViewtagValueMatcher.matches(view.getTag()Returns a matcher that matches Views based on tag property values.
static MatcherwithText(Matcher stringMatcher)获取是TextView及其子类类型的,并且其getText()的文本满足stringMatcher的ViewstringMatcher.matches(textView.getText().toString())Returns a matcher that matches TextViews based on text property value.
static MatcherwithText(String text)获取是TextView及其子类类型的,并且其getText()的文本 == text的ViewwithText(is(text)Returns a matcher that matches TextView based on its text property value.
static MatcherwithText(int resourceId)获取是TextView及其子类类型的,并且其getText()的文本 == resourceId对应的文本的ViewwithCharSequence(resourceId, TextViewMethod.GET_TEXT)Returns a matcher that matches a descendant of TextView that is displaying the string associated with the given resource id

2.2 RootMatchers 根视图匹配器的辅助类

匹配root装饰视图匹配给定的视图匹配器,也就是一系列静态方法,返回指定的 Matcher

onView(withText("Text"))
  .inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView()))))
  .perform(click());

RootMatchers还有以下方法可以应用到其他场景:

TablesAreCool
isDialog()匹配是对话框的根视图Matches {@link Root}s that are dialogs (i.e. is not a window of the currently resumed* activity).
isFocusable()匹配可获取焦点的根视图Matches {@link Root}s that can take window focus.
isPlatformPopup()匹配弹出式窗体的跟视图,如spinner,actionbar等Matches {@link Root}s that are popups - like autocomplete suggestions or the actionbar spinner.
isTouchable()匹配可触摸的根视图Matches {@link Root}s that can receive touch events.
withDecorView(final Matcher decorViewMatcher)指定view的跟视图Matches {@link Root}s with decor views that match the given view matcher

下面给几个简单应用

//指定View的跟视图不在当前的Activity根布局层次中,例如Toast
inRoot(withDecorView(not(mRules.getActivity().getWindow().getDecorView())))
inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView()))))

2.3 Matchers 对Matcher的操作集合类

  • allof(Matchers ) 满足Matchers 定义的所有Matcher
  • anyof(Matchers ) 至少满足Matchers 定义的任意一个Matcher
  • is(…)
  • not(…)
  • notNullValue()
  • nullValue()
  • endsWith(java.lang.String suffix)
  • startsWith(java.lang.String prefix)

2.4 CursorMatchers

Hamcrest的集合匹配器,在Cursor匹配相应的数据行

/**
   * Returns a matcher that matches a {@link String} value at a given column index
   * in a {@link Cursor}s data row.
   * <br>
   * @param columnIndex int column index
   * @param value a {@link String} value to match
   */
  public static CursorMatcher withRowString(int columnIndex, String value) {
    return withRowString(columnIndex, is(value));
  }

大部分的场景,大多发生于表单或者滚动menu时:

onData(
    is(instanceOf(Cursor.class)),
    CursorMatchers.withRowString("job_title", is("Barista"))
);

2.5 LayoutMatchers 匹配以检测典型的布局问题

例如匹配具有椭圆形文本的TextView元素。

如果文本太长,无法适应TextView,它可以是椭圆形(’Too long’显示为’Too l …’或’… long’)或切断(’Too long“显示为”Too l“)。

虽然在某些情况下可以接受,但通常表示不好的用户体验

2.6 PreferenceMatchers 匹配存储

Preference组件其实就是Android常见UI组件与SharePreferences的组合封装实现

onData(Matchers.<Object>allOf(PreferenceMatchers.withKey("setting-name"))).perform(click());

PreferenceMatchers还有以下方法可以应用到其他场景

withSummary(final int resourceId)
withSummaryText(String summary)
withSummaryText(final Matcher<String> summaryMatcher)
withTitle(final int resourceId)
withTitleText(String title)
withTitleText(final Matcher<String> titleMatcher)
isEnabled()

onView是根据View的相关属性来找到Interaction交互类
OnData则是根据 Data的相关属性来找到Interaction交互类

三、 AdapterView的OnData

  • ViewInteraction: 关注于已经匹配到的目标控件。通过onView()方法我们可以找到符合匹配条件的唯一的目标控件,我们只需要针对这个控件进行我们需要的操作

    • onView()
    • Matcher< View>: 构造一个针对于View匹配的匹配规则
  • DataInteraction: 关注于AdapterView的数据。由于AdapterView的数据源可能很长,很多时候无法一次性将所有数据源显示在屏幕上,因此我们主要先关注AdapterView中包含的数据,而非一次性就进行View的匹配。

    • onData
    • Matcher< ? extends Object>: 构造一个针对于Object(数据)匹配的匹配规则

onData 只适用于 AdapterView及其派生类,不适用于 RecyleView。

AdapterView是一种通过Adapter来动态加载数据的界面元素。我们常用的ListView, GridView, Spinner等等都属于AdapterView。不同于我们之前提到的静态的控件,AdapterView在加载数据时,可能只有一部分显示在了屏幕上,对于没有显示在屏幕上的那部分数据,我们通过onView()是没有办法找到的。

  • Matcher< ? extends Object>的构建规则:
    • 类型校验 : 确认AdapterView
    • 参数校验:确认item

注:初始化时就显示在屏幕上的adapter中的view你也可以不适用onData()因为他们已经被加载了。然而,使用onDta()会更加安全。

提醒:在打破了继承约束(尤其是getItem()的API)实现了AdatpterView的自定义view中onData()是有问题的。在这中情况下,做好的做法就是重构应用的代码。如果不重构代码,你也可以实现自定义的AdapterViewProtocol来实现。查看Espresso的AdapterViewProtocols 来查看更多信息。

3.1 简单类型

  • 类型校验
  • 参数校验
onData(allOf(is(instanceOf(String.class)),is("Americano"))).perform(click());

3.2 官方示例

这里写图片描述
如上 activity 包含一个 ListView,它基于一个为每一行提供一个 ​Map

onData(allOf(
        is(instanceOf(Map.class)), 
        hasEntry(equalTo("STR"), is("item: 50)
       ))
.perform(click());
3.2.1 is(instanceOf(Map.class)) 类型校验

限制搜索 AdapterView 中任意条目的条件为一个 Map。

在此例子中,ListView 的所有行都满足条件。但我们想要点击指定的条目 “item: 50”,所以我们需要继续缩小范围:

3.2.2 hasEntry(equalTo(“STR”), is(“item: 50)参数校验
 hasEntry(equalTo("STR"), is("item: 50)

优化:

这个 Matcher< String, Object > 会匹配所有包含任意键,值=“item: 50” 的 Map 。鉴于查找此条目的代码较长,而且我们希望在其他地方重用它,我们可以写一个自定义的 matcher “withItemContent”:

public static Matcher<Object> withItemContent(String expectedText) {
  checkNotNull(expectedText);
  return withItemContent(equalTo(expectedText));
}

public static Matcher<Object> withItemContent(Matcher itemTextMatcher) {
    return new BoundedMatcher<Object, Map>(Map.class) {
        @Override
        public boolean matchesSafely(Map map) {
          return hasEntry(equalTo("STR"), itemTextMatcher).matches(map);
        }

        @Override
        public void describeTo(Description description) {
          description.appendText("with item content: ");
          itemTextMatcher.describeTo(description);
        }
  };
}

现在点击该条目的代码很简单了:

onData(withItemContent("item: 50")).perform(click());

此测试的完整代码请查看 AdapterViewText#testClickOnItem50自定义匹配器

3.3 自定义Adapter:未打破继承约束

使用BoundedMatcher实现:

  • 类型校验
  • 参数校验

其实没啥说的,直接给个示例吧:

//根据销售机会名称查找到List中的item,并点击
onData(SaleOppMatcher.searchMainItemWithName(oppName)).perform(click());
    /**
     * 查找指定搜索条件  销售机会匹配
     * @param name 需要搜索的字
     */
    public static Matcher<Object> searchMainItemWithName(final String name) {
        return new BoundedMatcher<Object, SalesOpp>(SalesOpp.class) {
            @Override
            protected boolean matchesSafely(SalesOpp item) {
                return item != null
                        && !TextUtils.isEmpty(item.content)
                        && item.content.equals(name);
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("SalesOpp has Name: " + name);
            }
        };
    }

3.4 自定义Adapter:打破继承约束 usingAdapterViewProtocol

//根据客户拜访名称查找到List中的item,并点击
onData(LegWorkMatcher.searchMainItemWithName(legName)).perform(click());

3.5 OnData支持的筛选

onData我们使用了data进行了筛选,完全屏蔽了View,那么现在问题来了:

假设一个页面里有多个ListView,譬如“ViewPager+ListView的实现”

如果继续用上述方法,会出现:

android.support.test.espresso.AmbiguousViewMatcherException: ‘is assignable from class: class android.widget.AdapterView’ matches multiple views in the hierarchy. 
Problem views are marked with ‘*MATCHES*’ below.

大意就是说,有多个AdapterView在界面里,那么结局方案是:

  • inAdapterView(Matcher adapterMatcher)
onData(...).inAdapterView(allOf(isAssignableFrom(AdapterView.class),isDisplayed())).perform(click());

onData(...).inAdapterView(allOf(withId(R.id.list),isDisplayed())).perform(click());

现在我们详细的看看DataInteraction还支持那些筛选,来辅助onData:

Tables示意适用场景
inAdapterView(Matcher< View > adapterMatcher)选择 满足adapterMatcher的adapterview 来执行onData操作当前界面有多个adapterview,导致错误
onChildView(Matcher< View> childMatcher)匹配”onData所匹配的item视图”中的指定子视图需要点击item中的某个子view
atPosition(Integer atPosition)选中匹配的Adapter的第几项,默认不选择,可以通过atPosition方法设定onData只定义“类型校验”, onData(is(instanceOf(String.class)).atPosition(0)…
inRoot(Matcher< Root> rootMatcher)在指定跟视图中来执行onData操作对话框里的adapterview
  • PullToRefreshListView 如何使用inAdapterView?

PullToRefreshListView里面的ListView实际上是嵌套了一个id为android.R.id.list的ListView,因此可以用这个ID来进行匹配。如果单一匹配规则还不够精细,可以再从其他方面构造复合匹配规则。比如针对这种情况我采用了:

onData(allOf(is(instanceOf(TeacherModel.class)),teacherHasName(VALUE_TEACHER_NAME_TARGET)))
.inAdapterView(allOf(withId(android.R.id.list), isDisplayed()))
.perform(click());

3.6 匹配 ListView 的 footer/header 视图

header 和 footer 通过 addHeaderView/addFooterView API 添加到 ListView 中。为了能够使用 Espresso.onData 加载它们,确保使用预置的值来设置数据对象(第二个参数)。

public static final String FOOTER = "FOOTER";
...
View footerView = layoutInflater.inflate(R.layout.list_item, listView, false);
((TextView) footerView.findViewById(R.id.item_content)).setText("count:");
((TextView) footerView.findViewById(R.id.item_size)).setText(String.valueOf(data.size()));
listView.addFooterView(footerView, FOOTER, true);

然后,你可以写一个匹配器来匹配此对象:

import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;

@SuppressWarnings("unchecked")
public static Matcher<Object> isFooter() {
  return allOf(is(instanceOf(String.class)), is(LongListActivity.FOOTER));
}

在测试中很轻易就能加载该视图:

import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData;
import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click;
import static com.google.android.apps.common.testing.ui.espresso.sample.LongListMatchers.isFooter;

public void testClickFooter() {
  onData(isFooter())
    .perform(click());
  ...
}

请在 AdapterViewtest#testClickFooter 中查看完整示例代码。

四、RecyleView

RecyclerViews 和 AdapterViews 的工作原理不同,因此onData()不适用于RecyleView

如果想要与RecyleView交互,请引入“espresso-contrib”,里边包含一系列的Actions可以用于滚动和点击

//TODO 根据android.support.test.espresso.contrib.RecyclerViewActions揣摩RecyclerView的macher规则

4.1 actionOnItem源码解析

  public static <VH extends ViewHolder> PositionableRecyclerViewAction actionOnItem(
      final Matcher<View> itemViewMatcher, final ViewAction viewAction) {
    Matcher<VH> viewHolderMatcher = viewHolderMatcher(itemViewMatcher);
    return new ActionOnItemViewAction<VH>(viewHolderMatcher, viewAction);
  }
4.1.1 viewHolderMatcher
  /**
   * Creates matcher for view holder with given item view matcher.
   *
   * @param itemViewMatcher a item view matcher which is used to match item.
   * @return a matcher which matches a view holder containing item matching itemViewMatcher.
   */
  private static <VH extends ViewHolder> Matcher<VH> viewHolderMatcher(
      final Matcher<View> itemViewMatcher) {
    return new TypeSafeMatcher<VH>() {
      @Override
      public boolean matchesSafely(RecyclerView.ViewHolder viewHolder) {
        return itemViewMatcher.matches(viewHolder.itemView);
      }

      @Override
      public void describeTo(Description description) {
        description.appendText("holder with view: ");
        itemViewMatcher.describeTo(description);
      }
    };
  }

4.1.2 ActionOnItemViewAction

private static final class ActionOnItemViewAction<VH extends ViewHolder> implements
      PositionableRecyclerViewAction {
    private final Matcher<VH> viewHolderMatcher;
    private final ViewAction viewAction;
    private final int atPosition;
    private final ScrollToViewAction<VH> scroller;

    private ActionOnItemViewAction(Matcher<VH> viewHolderMatcher, ViewAction viewAction) {
      this(viewHolderMatcher, viewAction, NO_POSITION);
    }

    private ActionOnItemViewAction(Matcher<VH> viewHolderMatcher, ViewAction viewAction,
        int atPosition) {
      this.viewHolderMatcher = checkNotNull(viewHolderMatcher);
      this.viewAction = checkNotNull(viewAction);
      this.atPosition = atPosition;
      this.scroller = new ScrollToViewAction<VH>(viewHolderMatcher, atPosition);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Matcher<View> getConstraints() {
      return allOf(isAssignableFrom(RecyclerView.class), isDisplayed());
    }

    @Override
    public PositionableRecyclerViewAction atPosition(int position) {
      checkArgument(position >= 0, "%d is used as an index - must be >= 0", position);
      return new ActionOnItemViewAction<VH>(viewHolderMatcher, viewAction, position);
    }

    @Override
    public String getDescription() {
      if (atPosition == NO_POSITION) {
        return String.format("performing ViewAction: %s on item matching: %s",
            viewAction.getDescription(), viewHolderMatcher);

      } else {
        return String.format("performing ViewAction: %s on %d-th item matching: %s",
            viewAction.getDescription(), atPosition, viewHolderMatcher);
      }
    }

    @Override
    public void perform(UiController uiController, View root) {
      RecyclerView recyclerView = (RecyclerView) root;
      try {
        scroller.perform(uiController, root);
        uiController.loopMainThreadUntilIdle();
        // the above scroller has checked bounds, dupes (maybe) and brought the element into screen.
        int max = atPosition == NO_POSITION ? 2 : atPosition + 1;
        int selectIndex = atPosition == NO_POSITION ? 0 : atPosition;
        List<MatchedItem> matchedItems = itemsMatching(recyclerView, viewHolderMatcher, max);
        actionOnItemAtPosition(matchedItems.get(selectIndex).position, viewAction).perform(
            uiController, root);
        uiController.loopMainThreadUntilIdle();
      } catch (RuntimeException e) {
        throw new PerformException.Builder().withActionDescription(this.getDescription())
            .withViewDescription(HumanReadables.describe(root)).withCause(e).build();
      }
    }
  }

参考文献

[ 60%] Built target ydlidar_sdk [ 68%] Built target etlidar_test [ 76%] Built target tof_test [ 84%] Built target ydlidar_test [ 92%] Built target lidar_c_api_test [ 96%] Building CXX object test/CMakeFiles/lidar_test.dir/lidar_test.cpp.o In file included from /usr/include/gtest/gtest-message.h:57, from /usr/include/gtest/gtest-assertion-result.h:46, from /usr/include/gtest/gtest.h:64, from /home/a/ROS2教程/源码/YDLidar-SDK-master/test/lidar_test.h:4, from /home/a/ROS2教程/源码/YDLidar-SDK-master/test/lidar_test.cpp:1: /usr/include/gtest/internal/gtest-port.h:279:2: error: #error C++ versions less than C++14 are not supported. 279 | #error C++ versions less than C++14 are not supported. | ^~~~~ /usr/include/gtest/gtest-assertion-result.h: In member function &lsquo;void testing::AssertionResult::AppendMessage(const testing::Message&amp;)&rsquo;: /usr/include/gtest/gtest-assertion-result.h:207:48: error: &lsquo;make_unique&rsquo; is not a member of &lsquo;std&rsquo; 207 | if (message_ == nullptr) message_ = ::std::make_unique&lt;::std::string&gt;(); | ^~~~~~~~~~~ /usr/include/gtest/gtest-assertion-result.h:207:48: note: &lsquo;std::make_unique&rsquo; is only available from C++14 onwards /usr/include/gtest/gtest-assertion-result.h:207:73: error: expected primary-expression before &lsquo;&gt;&rsquo; token 207 | f (message_ == nullptr) message_ = ::std::make_unique&lt;::std::string&gt;(); | ^ /usr/include/gtest/gtest-assertion-result.h:207:75: error: expected primary-expression before &lsquo;)&rsquo; token 207 | f (message_ == nullptr) message_ = ::std::make_unique&lt;::std::string&gt;(); | ^ In file included from /usr/include/gtest/gtest-printers.h:122, from /usr/include/gtest/gtest-matchers.h:49, from /usr/include/gtest/internal/gtest-death-test-internal.h:47, from /usr/include/gtest/gtest-death-test.h:43, from /usr/include/gtest/gtest.h:65: /usr/include/gtest/internal/gtest-internal.h: At global scope: /usr/include/gtest/internal/gtest-internal.h:622:58: error: wrong number of template arguments (0, should be 1) 622 | typedef ::std::map&lt;std::string, CodeLocation, std::less&lt;&gt;&gt; RegisteredTestsMap; | ^ In file included from /usr/include/c++/13/string:49, from /usr/include/c++/13/bits/locale_classes.h:40, from /usr/include/c++/13/bits/ios_base.h:41, from /usr/include/c++/13/iomanip:42, from /usr/include/gtest/gtest.h:54: /usr/include/c++/13/bits/stl_function.h:403:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::less&rsquo; 403 | struct less : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~ /usr/include/gtest/internal/gtest-internal.h:622:59: error: template argument 3 is invalid 622 | typedef ::std::map&lt;std::string, CodeLocation, std::less&lt;&gt;&gt; RegisteredTestsMap; | ^~ /usr/include/gtest/internal/gtest-internal.h: In member function &lsquo;bool testing::internal::TypedTestSuitePState::AddTestName(const char*, int, const char*, const char*)&rsquo;: /usr/include/gtest/internal/gtest-internal.h:599:23: error: request for member &lsquo;insert&rsquo; in &lsquo;((testing::internal::TypedTestSuitePState*)this)-&gt;testing::internal::TypedTestSuitePState::registered_tests_&rsquo;, which is of non-class type &lsquo;testing::internal::TypedTestSuitePState::RegisteredTestsMap&rsquo; {aka &lsquo;int&rsquo;} 599 | registered_tests_.insert( | ^~~~~~ /usr/include/gtest/internal/gtest-internal.h: In member function &lsquo;bool testing::internal::TypedTestSuitePState::TestExists(const std::string&amp;) const&rsquo;: /usr/include/gtest/internal/gtest-internal.h:605:30: error: request for member &lsquo;count&rsquo; in &lsquo;((const testing::internal::TypedTestSuitePState*)this)-&gt;testing::internal::TypedTestSuitePState::registered_tests_&rsquo;, which is of non-class type &lsquo;const testing::internal::TypedTestSuitePState::RegisteredTestsMap&rsquo; {aka &lsquo;const int&rsquo;} 605 | return registered_tests_.count(test_name) &gt; 0; | ^~~~~ /usr/include/gtest/internal/gtest-internal.h: In member function &lsquo;const testing::internal::CodeLocation&amp; testing::internal::TypedTestSuitePState::GetCodeLocation(const std::string&amp;) const&rsquo;: /usr/include/gtest/internal/gtest-internal.h:609:40: error: qualified-id in declaration before &lsquo;it&rsquo; 609 | RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); | ^~ /usr/include/gtest/internal/gtest-internal.h:610:5: error: &lsquo;it&rsquo; was not declared in this scope; did you mean &lsquo;int&rsquo;? 610 | GTEST_CHECK_(it != registered_tests_.end()); | ^~~~~~~~~~~~ /usr/include/gtest/internal/gtest-internal.h:610:5: error: request for member &lsquo;end&rsquo; in &lsquo;((const testing::internal::TypedTestSuitePState*)this)-&gt;testing::internal::TypedTestSuitePState::registered_tests_&rsquo;, which is of non-class type &lsquo;const testing::internal::TypedTestSuitePState::RegisteredTestsMap&rsquo; {aka &lsquo;const int&rsquo;} 610 | GTEST_CHECK_(it != registered_tests_.end()); | ^~~~~~~~~~~~ /usr/include/gtest/internal/gtest-internal.h:611:12: error: &lsquo;it&rsquo; was not declared in this scope; did you mean &lsquo;int&rsquo;? 611 | return it-&gt;second; | ^~ | int /usr/include/gtest/gtest-matchers.h: At global scope: /usr/include/gtest/gtest-matchers.h:725:75: error: wrong number of template arguments (0, should be 1) 725 | Matcher : public ComparisonBase&lt;EqMatcher&lt;Rhs&gt;, Rhs, std::equal_to&lt;&gt;&gt; { | ^ /usr/include/c++/13/bits/stl_function.h:373:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::equal_to&rsquo; 373 | struct equal_to : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~~ /usr/include/gtest/gtest-matchers.h:725:76: error: template argument 3 is invalid 725 | Matcher : public ComparisonBase&lt;EqMatcher&lt;Rhs&gt;, Rhs, std::equal_to&lt;&gt;&gt; { | ^~ /usr/include/gtest/gtest-matchers.h: In constructor &lsquo;testing::internal::EqMatcher&lt;Rhs&gt;::EqMatcher(const Rhs&amp;)&rsquo;: /usr/include/gtest/gtest-matchers.h:728:58: error: wrong number of template arguments (0, should be 1) 728 | : ComparisonBase&lt;EqMatcher&lt;Rhs&gt;, Rhs, std::equal_to&lt;&gt;&gt;(rhs) {} | ^ /usr/include/c++/13/bits/stl_function.h:373:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::equal_to&rsquo; 373 | struct equal_to : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~~ /usr/include/gtest/gtest-matchers.h:728:59: error: template argument 3 is invalid 728 | : ComparisonBase&lt;EqMatcher&lt;Rhs&gt;, Rhs, std::equal_to&lt;&gt;&gt;(rhs) {} | ^~ /usr/include/gtest/gtest-matchers.h:728:61: error: expected &lsquo;{&rsquo; before &lsquo;(&rsquo; token 728 | : ComparisonBase&lt;EqMatcher&lt;Rhs&gt;, Rhs, std::equal_to&lt;&gt;&gt;(rhs) {} | ^ /usr/include/gtest/gtest-matchers.h: At global scope: /usr/include/gtest/gtest-matchers.h:734:67: error: wrong number of template arguments (0, should be 1) 734 | : public ComparisonBase&lt;NeMatcher&lt;Rhs&gt;, Rhs, std::not_equal_to&lt;&gt;&gt; { | ^ /usr/include/c++/13/bits/stl_function.h:383:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::not_equal_to&rsquo; 383 | struct not_equal_to : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~~~~~~ /usr/include/gtest/gtest-matchers.h:734:68: error: template argument 3 is invalid 734 | : public ComparisonBase&lt;NeMatcher&lt;Rhs&gt;, Rhs, std::not_equal_to&lt;&gt;&gt; { | ^~ /usr/include/gtest/gtest-matchers.h: In constructor &lsquo;testing::internal::NeMatcher&lt;Rhs&gt;::NeMatcher(const Rhs&amp;)&rsquo;: /usr/include/gtest/gtest-matchers.h:737:62: error: wrong number of template arguments (0, should be 1) 737 | : ComparisonBase&lt;NeMatcher&lt;Rhs&gt;, Rhs, std::not_equal_to&lt;&gt;&gt;(rhs) {} | ^ /usr/include/c++/13/bits/stl_function.h:383:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::not_equal_to&rsquo; 383 | struct not_equal_to : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~~~~~~ /usr/include/gtest/gtest-matchers.h:737:63: error: template argument 3 is invalid 737 | : ComparisonBase&lt;NeMatcher&lt;Rhs&gt;, Rhs, std::not_equal_to&lt;&gt;&gt;(rhs) {} | ^~ /usr/include/gtest/gtest-matchers.h:737:65: error: expected &lsquo;{&rsquo; before &lsquo;(&rsquo; token 737 | : ComparisonBase&lt;NeMatcher&lt;Rhs&gt;, Rhs, std::not_equal_to&lt;&gt;&gt;(rhs) {} | ^ /usr/include/gtest/gtest-matchers.h: At global scope: /usr/include/gtest/gtest-matchers.h:742:71: error: wrong number of template arguments (0, should be 1) 742 | s LtMatcher : public ComparisonBase&lt;LtMatcher&lt;Rhs&gt;, Rhs, std::less&lt;&gt;&gt; { | ^ /usr/include/c++/13/bits/stl_function.h:403:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::less&rsquo; 403 | struct less : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~ /usr/include/gtest/gtest-matchers.h:742:72: error: template argument 3 is invalid 742 | s LtMatcher : public ComparisonBase&lt;LtMatcher&lt;Rhs&gt;, Rhs, std::less&lt;&gt;&gt; { | ^~ /usr/include/gtest/gtest-matchers.h: In constructor &lsquo;testing::internal::LtMatcher&lt;Rhs&gt;::LtMatcher(const Rhs&amp;)&rsquo;: /usr/include/gtest/gtest-matchers.h:745:54: error: wrong number of template arguments (0, should be 1) 745 | : ComparisonBase&lt;LtMatcher&lt;Rhs&gt;, Rhs, std::less&lt;&gt;&gt;(rhs) {} | ^ /usr/include/c++/13/bits/stl_function.h:403:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::less&rsquo; 403 | struct less : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~ /usr/include/gtest/gtest-matchers.h:745:55: error: template argument 3 is invalid 745 | : ComparisonBase&lt;LtMatcher&lt;Rhs&gt;, Rhs, std::less&lt;&gt;&gt;(rhs) {} | ^~ /usr/include/gtest/gtest-matchers.h:745:57: error: expected &lsquo;{&rsquo; before &lsquo;(&rsquo; token 745 | : ComparisonBase&lt;LtMatcher&lt;Rhs&gt;, Rhs, std::less&lt;&gt;&gt;(rhs) {} | ^ /usr/include/gtest/gtest-matchers.h: At global scope: /usr/include/gtest/gtest-matchers.h:750:74: error: wrong number of template arguments (0, should be 1) 750 | tMatcher : public ComparisonBase&lt;GtMatcher&lt;Rhs&gt;, Rhs, std::greater&lt;&gt;&gt; { | ^ /usr/include/c++/13/bits/stl_function.h:393:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::greater&rsquo; 393 | struct greater : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~ /usr/include/gtest/gtest-matchers.h:750:75: error: template argument 3 is invalid 750 | tMatcher : public ComparisonBase&lt;GtMatcher&lt;Rhs&gt;, Rhs, std::greater&lt;&gt;&gt; { | ^~ /usr/include/gtest/gtest-matchers.h: In constructor &lsquo;testing::internal::GtMatcher&lt;Rhs&gt;::GtMatcher(const Rhs&amp;)&rsquo;: /usr/include/gtest/gtest-matchers.h:753:57: error: wrong number of template arguments (0, should be 1) 753 | : ComparisonBase&lt;GtMatcher&lt;Rhs&gt;, Rhs, std::greater&lt;&gt;&gt;(rhs) {} | ^ /usr/include/c++/13/bits/stl_function.h:393:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::greater&rsquo; 393 | struct greater : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~ /usr/include/gtest/gtest-matchers.h:753:58: error: template argument 3 is invalid 753 | : ComparisonBase&lt;GtMatcher&lt;Rhs&gt;, Rhs, std::greater&lt;&gt;&gt;(rhs) {} | ^~ /usr/include/gtest/gtest-matchers.h:753:60: error: expected &lsquo;{&rsquo; before &lsquo;(&rsquo; token 753 | : ComparisonBase&lt;GtMatcher&lt;Rhs&gt;, Rhs, std::greater&lt;&gt;&gt;(rhs) {} | ^ /usr/include/gtest/gtest-matchers.h: At global scope: /usr/include/gtest/gtest-matchers.h:759:65: error: wrong number of template arguments (0, should be 1) 759 | : public ComparisonBase&lt;LeMatcher&lt;Rhs&gt;, Rhs, std::less_equal&lt;&gt;&gt; { | ^ /usr/include/c++/13/bits/stl_function.h:423:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::less_equal&rsquo; 423 | struct less_equal : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~~~~ /usr/include/gtest/gtest-matchers.h:759:66: error: template argument 3 is invalid 759 | : public ComparisonBase&lt;LeMatcher&lt;Rhs&gt;, Rhs, std::less_equal&lt;&gt;&gt; { | ^~ /usr/include/gtest/gtest-matchers.h: In constructor &lsquo;testing::internal::LeMatcher&lt;Rhs&gt;::LeMatcher(const Rhs&amp;)&rsquo;: /usr/include/gtest/gtest-matchers.h:762:60: error: wrong number of template arguments (0, should be 1) 762 | : ComparisonBase&lt;LeMatcher&lt;Rhs&gt;, Rhs, std::less_equal&lt;&gt;&gt;(rhs) {} | ^ /usr/include/c++/13/bits/stl_function.h:423:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::less_equal&rsquo; 423 | struct less_equal : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~~~~ /usr/include/gtest/gtest-matchers.h:762:61: error: template argument 3 is invalid 762 | : ComparisonBase&lt;LeMatcher&lt;Rhs&gt;, Rhs, std::less_equal&lt;&gt;&gt;(rhs) {} | ^~ /usr/include/gtest/gtest-matchers.h:762:63: error: expected &lsquo;{&rsquo; before &lsquo;(&rsquo; token 762 | : ComparisonBase&lt;LeMatcher&lt;Rhs&gt;, Rhs, std::less_equal&lt;&gt;&gt;(rhs) {} | ^ /usr/include/gtest/gtest-matchers.h: At global scope: /usr/include/gtest/gtest-matchers.h:768:68: error: wrong number of template arguments (0, should be 1) 768 | : public ComparisonBase&lt;GeMatcher&lt;Rhs&gt;, Rhs, std::greater_equal&lt;&gt;&gt; { | ^ /usr/include/c++/13/bits/stl_function.h:413:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::greater_equal&rsquo; 413 | struct greater_equal : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~~~~~~~ /usr/include/gtest/gtest-matchers.h:768:69: error: template argument 3 is invalid 768 | : public ComparisonBase&lt;GeMatcher&lt;Rhs&gt;, Rhs, std::greater_equal&lt;&gt;&gt; { | ^~ /usr/include/gtest/gtest-matchers.h: In constructor &lsquo;testing::internal::GeMatcher&lt;Rhs&gt;::GeMatcher(const Rhs&amp;)&rsquo;: /usr/include/gtest/gtest-matchers.h:771:63: error: wrong number of template arguments (0, should be 1) 771 | : ComparisonBase&lt;GeMatcher&lt;Rhs&gt;, Rhs, std::greater_equal&lt;&gt;&gt;(rhs) {} | ^ /usr/include/c++/13/bits/stl_function.h:413:12: note: provided for &lsquo;template&lt;class _Tp&gt; struct std::greater_equal&rsquo; 413 | struct greater_equal : public binary_function&lt;_Tp, _Tp, bool&gt; | ^~~~~~~~~~~~~ /usr/include/gtest/gtest-matchers.h:771:64: error: template argument 3 is invalid 771 | : ComparisonBase&lt;GeMatcher&lt;Rhs&gt;, Rhs, std::greater_equal&lt;&gt;&gt;(rhs) {} | ^~ /usr/include/gtest/gtest-matchers.h:771:66: error: expected &lsquo;{&rsquo; before &lsquo;(&rsquo; token 771 | : ComparisonBase&lt;GeMatcher&lt;Rhs&gt;, Rhs, std::greater_equal&lt;&gt;&gt;(rhs) {} | ^ /usr/include/gtest/gtest.h: At global scope: /usr/include/gtest/gtest.h:302:30: error: &lsquo;std::enable_if_t&rsquo; has not been declared 302 | template &lt;typename T, std::enable_if_t&lt;std::is_convertible&lt;T, int64_t&gt;::value, | ^~~~~~~~~~~ /usr/include/gtest/gtest.h:302:41: error: expected &lsquo;&gt;&rsquo; before &lsquo;&lt;&rsquo; token 302 | template &lt;typename T, std::enable_if_t&lt;std::is_convertible&lt;T, int64_t&gt;::value, | ^ make[2]: *** [test/CMakeFiles/lidar_test.dir/build.make:76:test/CMakeFiles/lidar_test.dir/lidar_test.cpp.o] 错误 1 make[1]: *** [CMakeFiles/Makefile2:449:test/CMakeFiles/lidar_test.dir/all] 错误 2 make: *** [Makefile:166:all] 错误 2
05-28
D:\software\Java\jdk1.8.0_451\bin\java.exe -Dvisualgc.id=3111897454531800 -ea -Didea.test.cyclic.buffer.size=1048576 &quot;-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.7\lib\idea_rt.jar=5415:C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.7\bin&quot; -Dfile.encoding=UTF-8 -classpath &quot;C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.7\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.7\plugins\junit\lib\junit5-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.7\plugins\junit\lib\junit-rt.jar;D:\software\Java\jdk1.8.0_451\jre\lib\charsets.jar;D:\software\Java\jdk1.8.0_451\jre\lib\deploy.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\access-bridge-64.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\cldrdata.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\dnsns.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\jaccess.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\localedata.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\nashorn.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\sunec.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\sunjce_provider.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\sunmscapi.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\sunpkcs11.jar;D:\software\Java\jdk1.8.0_451\jre\lib\ext\zipfs.jar;D:\software\Java\jdk1.8.0_451\jre\lib\javaws.jar;D:\software\Java\jdk1.8.0_451\jre\lib\jce.jar;D:\software\Java\jdk1.8.0_451\jre\lib\jfr.jar;D:\software\Java\jdk1.8.0_451\jre\lib\jsse.jar;D:\software\Java\jdk1.8.0_451\jre\lib\management-agent.jar;D:\software\Java\jdk1.8.0_451\jre\lib\plugin.jar;D:\software\Java\jdk1.8.0_451\jre\lib\resources.jar;D:\software\Java\jdk1.8.0_451\jre\lib\rt.jar;D:\workspace\git_localrepo\access-control\person\person-core\target\test-classes;D:\workspace\git_localrepo\access-control\person\person-core\target\classes;D:\workspace\git_localrepo\access-control\person\person-api\target\classes;D:\workspace\git_localrepo\access-control\person\person-port-repository-api\target\classes;F:\Program Files\repository\org\springframework\data\spring-data-mongodb\3.4.7\spring-data-mongodb-3.4.7.jar;F:\Program Files\repository\org\springframework\spring-tx\5.3.25\spring-tx-5.3.25.jar;F:\Program Files\repository\org\springframework\spring-context\5.3.25\spring-context-5.3.25.jar;F:\Program Files\repository\org\springframework\spring-aop\5.3.25\spring-aop-5.3.25.jar;F:\Program Files\repository\org\springframework\spring-beans\5.3.25\spring-beans-5.3.25.jar;F:\Program Files\repository\org\springframework\spring-expression\5.3.25\spring-expression-5.3.25.jar;F:\Program Files\repository\org\springframework\data\spring-data-commons\2.7.7\spring-data-commons-2.7.7.jar;F:\Program Files\repository\org\mongodb\mongodb-driver-core\4.6.1\mongodb-driver-core-4.6.1.jar;F:\Program Files\repository\org\mongodb\bson\4.6.1\bson-4.6.1.jar;F:\Program Files\repository\org\mongodb\bson-record-codec\4.6.1\bson-record-codec-4.6.1.jar;F:\Program Files\repository\com\tplink\cdd\vigi-common-mongo\2.0.105-SNAPSHOT\vigi-common-mongo-2.0.105-SNAPSHOT.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-starter-data-mongodb\2.7.8\spring-boot-starter-data-mongodb-2.7.8.jar;F:\Program Files\repository\org\mongodb\mongodb-driver-sync\4.6.1\mongodb-driver-sync-4.6.1.jar;F:\Program Files\repository\com\tplink\cdd\vigi-common\2.0.105-SNAPSHOT\vigi-common-2.0.105-SNAPSHOT.jar;F:\Program Files\repository\com\google\guava\guava\29.0-jre\guava-29.0-jre.jar;F:\Program Files\repository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;F:\Program Files\repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;F:\Program Files\repository\org\checkerframework\checker-qual\2.11.1\checker-qual-2.11.1.jar;F:\Program Files\repository\com\google\errorprone\error_prone_annotations\2.3.4\error_prone_annotations-2.3.4.jar;F:\Program Files\repository\com\google\j2objc\j2objc-annotations\1.3\j2objc-annotations-1.3.jar;F:\Program Files\repository\org\json\json\20230227\json-20230227.jar;F:\Program Files\repository\com\fasterxml\jackson\core\jackson-databind\2.13.4.2\jackson-databind-2.13.4.2.jar;F:\Program Files\repository\cn\hutool\hutool-core\5.8.15\hutool-core-5.8.15.jar;F:\Program Files\repository\cn\hutool\hutool-crypto\5.8.15\hutool-crypto-5.8.15.jar;F:\Program Files\repository\javax\validation\validation-api\2.0.1.Final\validation-api-2.0.1.Final.jar;F:\Program Files\repository\org\hibernate\validator\hibernate-validator\6.2.5.Final\hibernate-validator-6.2.5.Final.jar;F:\Program Files\repository\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;F:\Program Files\repository\org\jboss\logging\jboss-logging\3.4.3.Final\jboss-logging-3.4.3.Final.jar;F:\Program Files\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;F:\Program Files\repository\org\springframework\boot\spring-boot\2.7.8\spring-boot-2.7.8.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-configuration-processor\2.7.8\spring-boot-configuration-processor-2.7.8.jar;F:\Program Files\repository\org\springframework\spring-web\5.3.25\spring-web-5.3.25.jar;F:\Program Files\repository\io\micrometer\micrometer-registry-prometheus\1.9.7\micrometer-registry-prometheus-1.9.7.jar;F:\Program Files\repository\io\prometheus\simpleclient_common\0.15.0\simpleclient_common-0.15.0.jar;F:\Program Files\repository\io\prometheus\simpleclient\0.15.0\simpleclient-0.15.0.jar;F:\Program Files\repository\io\prometheus\simpleclient_tracer_otel\0.15.0\simpleclient_tracer_otel-0.15.0.jar;F:\Program Files\repository\io\prometheus\simpleclient_tracer_common\0.15.0\simpleclient_tracer_common-0.15.0.jar;F:\Program Files\repository\io\prometheus\simpleclient_tracer_otel_agent\0.15.0\simpleclient_tracer_otel_agent-0.15.0.jar;F:\Program Files\repository\com\tplink\nbu\common\platform-cloud-sdk\2.1.60\platform-cloud-sdk-2.1.60.jar;F:\Program Files\repository\org\apache\httpcomponents\httpasyncclient\4.1.5\httpasyncclient-4.1.5.jar;F:\Program Files\repository\org\apache\httpcomponents\httpcore-nio\4.4.16\httpcore-nio-4.4.16.jar;F:\Program Files\repository\com\tplink\nbu\common\nbu-common-utils\2.1.60\nbu-common-utils-2.1.60.jar;F:\Program Files\repository\org\softee\pojo-mbean\1.1\pojo-mbean-1.1.jar;F:\Program Files\repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;F:\Program Files\repository\com\tplink\nbu\common\pii\2.1.60\pii-2.1.60.jar;F:\Program Files\repository\com\jayway\jsonpath\json-path\2.7.0\json-path-2.7.0.jar;F:\Program Files\repository\net\minidev\json-smart\2.4.8\json-smart-2.4.8.jar;F:\Program Files\repository\net\minidev\accessors-smart\2.4.8\accessors-smart-2.4.8.jar;F:\Program Files\repository\org\ow2\asm\asm\9.1\asm-9.1.jar;F:\Program Files\repository\javax\servlet\javax.servlet-api\4.0.1\javax.servlet-api-4.0.1.jar;F:\Program Files\repository\io\netty\netty-all\4.1.87.Final\netty-all-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-buffer\4.1.87.Final\netty-buffer-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec\4.1.87.Final\netty-codec-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-dns\4.1.87.Final\netty-codec-dns-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-haproxy\4.1.87.Final\netty-codec-haproxy-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-http\4.1.87.Final\netty-codec-http-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-http2\4.1.87.Final\netty-codec-http2-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-memcache\4.1.87.Final\netty-codec-memcache-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-mqtt\4.1.87.Final\netty-codec-mqtt-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-redis\4.1.87.Final\netty-codec-redis-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-smtp\4.1.87.Final\netty-codec-smtp-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-socks\4.1.87.Final\netty-codec-socks-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-stomp\4.1.87.Final\netty-codec-stomp-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-codec-xml\4.1.87.Final\netty-codec-xml-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-common\4.1.87.Final\netty-common-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-handler\4.1.87.Final\netty-handler-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-transport-native-unix-common\4.1.87.Final\netty-transport-native-unix-common-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-handler-proxy\4.1.87.Final\netty-handler-proxy-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-handler-ssl-ocsp\4.1.87.Final\netty-handler-ssl-ocsp-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-resolver\4.1.87.Final\netty-resolver-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-resolver-dns\4.1.87.Final\netty-resolver-dns-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-transport\4.1.87.Final\netty-transport-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-transport-rxtx\4.1.87.Final\netty-transport-rxtx-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-transport-sctp\4.1.87.Final\netty-transport-sctp-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-transport-udt\4.1.87.Final\netty-transport-udt-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-transport-classes-epoll\4.1.87.Final\netty-transport-classes-epoll-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-transport-classes-kqueue\4.1.87.Final\netty-transport-classes-kqueue-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-resolver-dns-classes-macos\4.1.87.Final\netty-resolver-dns-classes-macos-4.1.87.Final.jar;F:\Program Files\repository\io\netty\netty-transport-native-epoll\4.1.87.Final\netty-transport-native-epoll-4.1.87.Final-linux-x86_64.jar;F:\Program Files\repository\io\netty\netty-transport-native-epoll\4.1.87.Final\netty-transport-native-epoll-4.1.87.Final-linux-aarch_64.jar;F:\Program Files\repository\io\netty\netty-transport-native-kqueue\4.1.87.Final\netty-transport-native-kqueue-4.1.87.Final-osx-x86_64.jar;F:\Program Files\repository\io\netty\netty-transport-native-kqueue\4.1.87.Final\netty-transport-native-kqueue-4.1.87.Final-osx-aarch_64.jar;F:\Program Files\repository\io\netty\netty-resolver-dns-native-macos\4.1.87.Final\netty-resolver-dns-native-macos-4.1.87.Final-osx-x86_64.jar;F:\Program Files\repository\io\netty\netty-resolver-dns-native-macos\4.1.87.Final\netty-resolver-dns-native-macos-4.1.87.Final-osx-aarch_64.jar;F:\Program Files\repository\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar;F:\Program Files\repository\net\sourceforge\javacsv\javacsv\2.0\javacsv-2.0.jar;F:\Program Files\repository\com\googlecode\java-ipv6\java-ipv6\0.17\java-ipv6-0.17.jar;F:\Program Files\repository\org\apache\poi\poi-ooxml\4.1.2\poi-ooxml-4.1.2.jar;F:\Program Files\repository\org\apache\poi\poi\4.1.2\poi-4.1.2.jar;F:\Program Files\repository\org\apache\commons\commons-collections4\4.4\commons-collections4-4.4.jar;F:\Program Files\repository\org\apache\commons\commons-math3\3.6.1\commons-math3-3.6.1.jar;F:\Program Files\repository\com\zaxxer\SparseBitSet\1.2\SparseBitSet-1.2.jar;F:\Program Files\repository\org\apache\poi\poi-ooxml-schemas\4.1.2\poi-ooxml-schemas-4.1.2.jar;F:\Program Files\repository\org\apache\xmlbeans\xmlbeans\3.1.0\xmlbeans-3.1.0.jar;F:\Program Files\repository\org\apache\commons\commons-compress\1.19\commons-compress-1.19.jar;F:\Program Files\repository\com\github\virtuald\curvesapi\1.06\curvesapi-1.06.jar;F:\Program Files\repository\org\bouncycastle\bcprov-jdk15on\1.68\bcprov-jdk15on-1.68.jar;F:\Program Files\repository\org\bouncycastle\bcpkix-jdk15on\1.68\bcpkix-jdk15on-1.68.jar;F:\Program Files\repository\org\mapstruct\mapstruct\1.4.2.Final\mapstruct-1.4.2.Final.jar;F:\Program Files\repository\org\mapstruct\mapstruct-processor\1.4.2.Final\mapstruct-processor-1.4.2.Final.jar;F:\Program Files\repository\org\apache\skywalking\apm-toolkit-log4j-2.x\8.1.0\apm-toolkit-log4j-2.x-8.1.0.jar;F:\Program Files\repository\org\apache\skywalking\apm-toolkit-trace\8.1.0\apm-toolkit-trace-8.1.0.jar;F:\Program Files\repository\com\tplink\nbu\skywalking-sdk\1.0.0\skywalking-sdk-1.0.0.jar;F:\Program Files\repository\io\grpc\grpc-netty-shaded\1.27.1\grpc-netty-shaded-1.27.1.jar;F:\Program Files\repository\io\grpc\grpc-core\1.27.1\grpc-core-1.27.1.jar;F:\Program Files\repository\io\grpc\grpc-api\1.27.1\grpc-api-1.27.1.jar;F:\Program Files\repository\io\grpc\grpc-context\1.27.1\grpc-context-1.27.1.jar;F:\Program Files\repository\org\codehaus\mojo\animal-sniffer-annotations\1.18\animal-sniffer-annotations-1.18.jar;F:\Program Files\repository\com\google\code\gson\gson\2.9.1\gson-2.9.1.jar;F:\Program Files\repository\com\google\android\annotations\4.1.1.4\annotations-4.1.1.4.jar;F:\Program Files\repository\io\perfmark\perfmark-api\0.19.0\perfmark-api-0.19.0.jar;F:\Program Files\repository\org\apache\httpcomponents\httpclient\4.5.14\httpclient-4.5.14.jar;F:\Program Files\repository\org\apache\httpcomponents\httpcore\4.4.16\httpcore-4.4.16.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-starter\2.7.8\spring-boot-starter-2.7.8.jar;F:\Program Files\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;F:\Program Files\repository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-starter-log4j2\2.7.8\spring-boot-starter-log4j2-2.7.8.jar;F:\Program Files\repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;F:\Program Files\repository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;F:\Program Files\repository\org\apache\logging\log4j\log4j-slf4j-impl\2.17.2\log4j-slf4j-impl-2.17.2.jar;F:\Program Files\repository\org\apache\logging\log4j\log4j-core\2.17.2\log4j-core-2.17.2.jar;F:\Program Files\repository\org\apache\logging\log4j\log4j-jul\2.17.2\log4j-jul-2.17.2.jar;F:\Program Files\repository\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;F:\Program Files\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;F:\Program Files\repository\com\tplink\cdd\vigi-common-eventbus\2.0.105-SNAPSHOT\vigi-common-eventbus-2.0.105-SNAPSHOT.jar;F:\Program Files\repository\com\tplink\smb\eventcenter.api\1.4.5\eventcenter.api-1.4.5.jar;F:\Program Files\repository\com\tplink\cdd\vigi-common-tpcloud\2.0.105-SNAPSHOT\vigi-common-tpcloud-2.0.105-SNAPSHOT.jar;F:\Program Files\repository\com\tplink\account-api-sdk\1.3.172\account-api-sdk-1.3.172.jar;F:\Program Files\repository\com\tplink\platform\common-grpc\1.0.4\common-grpc-1.0.4.jar;F:\Program Files\repository\com\google\protobuf\protobuf-java\3.19.2\protobuf-java-3.19.2.jar;F:\Program Files\repository\com\tplink\nbu\common\pii-mask-spring-boot-autoconfigure\2.1.51\pii-mask-spring-boot-autoconfigure-2.1.51.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-starter-web\2.7.8\spring-boot-starter-web-2.7.8.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-starter-json\2.7.8\spring-boot-starter-json-2.7.8.jar;F:\Program Files\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.4\jackson-datatype-jdk8-2.13.4.jar;F:\Program Files\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.4\jackson-module-parameter-names-2.13.4.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-starter-tomcat\2.7.8\spring-boot-starter-tomcat-2.7.8.jar;F:\Program Files\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.71\tomcat-embed-websocket-9.0.71.jar;F:\Program Files\repository\org\springframework\spring-webmvc\5.3.25\spring-webmvc-5.3.25.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-starter-validation\2.7.8\spring-boot-starter-validation-2.7.8.jar;F:\Program Files\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.71\tomcat-embed-el-9.0.71.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-starter-actuator\2.7.8\spring-boot-starter-actuator-2.7.8.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-actuator-autoconfigure\2.7.8\spring-boot-actuator-autoconfigure-2.7.8.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-actuator\2.7.8\spring-boot-actuator-2.7.8.jar;F:\Program Files\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.4\jackson-datatype-jsr310-2.13.4.jar;F:\Program Files\repository\com\hubspot\jackson\jackson-datatype-protobuf\0.9.15\jackson-datatype-protobuf-0.9.15.jar;F:\Program Files\repository\com\google\protobuf\protobuf-java-util\3.19.3\protobuf-java-util-3.19.3.jar;F:\Program Files\repository\com\google\code\findbugs\annotations\3.0.1\annotations-3.0.1.jar;F:\Program Files\repository\com\tplink\account-sdk\1.3.172\account-sdk-1.3.172.jar;F:\Program Files\repository\com\tplink\account\auth-sdk\1.1.621\auth-sdk-1.1.621.jar;F:\Program Files\repository\com\tplink\common\mail-sdk\1.1.507\mail-sdk-1.1.507.jar;F:\Program Files\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.71\tomcat-embed-core-9.0.71.jar;F:\Program Files\repository\org\apache\tomcat\tomcat-annotations-api\9.0.71\tomcat-annotations-api-9.0.71.jar;F:\Program Files\repository\com\tplink\cdd\common\components-email-cloud-platform\1.0.11\components-email-cloud-platform-1.0.11.jar;F:\Program Files\repository\com\tplink\cdd\common\components-email-api\1.0.11\components-email-api-1.0.11.jar;F:\Program Files\repository\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;F:\Program Files\repository\com\tplink\cdd\common\components-email-common\1.0.11\components-email-common-1.0.11.jar;F:\Program Files\repository\com\tplink\smb\solution-components-lock-api\1.1.5\solution-components-lock-api-1.1.5.jar;F:\Program Files\repository\org\springframework\boot\spring-boot-autoconfigure\2.7.8\spring-boot-autoconfigure-2.7.8.jar;F:\Program Files\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;F:\Program Files\repository\com\tplink\smb\solution-components-cache-api\1.4.3\solution-components-cache-api-1.4.3.jar;F:\Program Files\repository\com\tplink\smb\solution-components-cache-mem\1.4.3\solution-components-cache-mem-1.4.3.jar;F:\Program Files\repository\com\github\ben-manes\caffeine\caffeine\2.9.3\caffeine-2.9.3.jar;F:\Program Files\repository\com\tplink\smb\solution-component-storage-api\1.4.10\solution-component-storage-api-1.4.10.jar;F:\Program Files\repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;F:\Program Files\repository\com\tplink\smb\solution-component-storage-port-s3\1.4.10\solution-component-storage-port-s3-1.4.10.jar;F:\Program Files\repository\com\amazonaws\aws-java-sdk-s3\1.12.415\aws-java-sdk-s3-1.12.415.jar;F:\Program Files\repository\com\amazonaws\aws-java-sdk-kms\1.12.415\aws-java-sdk-kms-1.12.415.jar;F:\Program Files\repository\com\amazonaws\aws-java-sdk-core\1.12.415\aws-java-sdk-core-1.12.415.jar;F:\Program Files\repository\commons-logging\commons-logging\1.1.3\commons-logging-1.1.3.jar;F:\Program Files\repository\software\amazon\ion\ion-java\1.0.2\ion-java-1.0.2.jar;F:\Program Files\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-cbor\2.13.4\jackson-dataformat-cbor-2.13.4.jar;F:\Program Files\repository\joda-time\joda-time\2.8.1\joda-time-2.8.1.jar;F:\Program Files\repository\com\amazonaws\jmespath-java\1.12.415\jmespath-java-1.12.415.jar;F:\Program Files\repository\com\amazonaws\aws-java-sdk-sts\1.12.415\aws-java-sdk-sts-1.12.415.jar;F:\Program Files\repository\com\tplink\cdd\vigi-common-algorithm\2.0.105-SNAPSHOT\vigi-common-algorithm-2.0.105-SNAPSHOT.jar;F:\Program Files\repository\com\amazonaws\aws-java-sdk-lambda\1.11.923\aws-java-sdk-lambda-1.11.923.jar;F:\Program Files\repository\com\tplink\smb\eventcenter.kafka\1.4.5\eventcenter.kafka-1.4.5.jar;F:\Program Files\repository\com\tplink\smb\eventcenter.core\1.4.5\eventcenter.core-1.4.5.jar;F:\Program Files\repository\org\springframework\kafka\spring-kafka\2.8.11\spring-kafka-2.8.11.jar;F:\Program Files\repository\org\springframework\spring-messaging\5.3.25\spring-messaging-5.3.25.jar;F:\Program Files\repository\org\springframework\retry\spring-retry\1.3.4\spring-retry-1.3.4.jar;F:\Program Files\repository\org\apache\kafka\kafka-clients\3.1.2\kafka-clients-3.1.2.jar;F:\Program Files\repository\com\github\luben\zstd-jni\1.5.0-4\zstd-jni-1.5.0-4.jar;F:\Program Files\repository\org\lz4\lz4-java\1.8.0\lz4-java-1.8.0.jar;F:\Program Files\repository\org\xerial\snappy\snappy-java\1.1.8.4\snappy-java-1.1.8.4.jar;F:\Program Files\repository\io\micrometer\micrometer-core\1.9.7\micrometer-core-1.9.7.jar;F:\Program Files\repository\org\hdrhistogram\HdrHistogram\2.1.12\HdrHistogram-2.1.12.jar;F:\Program Files\repository\org\latencyutils\LatencyUtils\2.0.3\LatencyUtils-2.0.3.jar;F:\Program Files\repository\io\github\resilience4j\resilience4j-circuitbreaker\1.3.0\resilience4j-circuitbreaker-1.3.0.jar;F:\Program Files\repository\io\vavr\vavr\0.10.2\vavr-0.10.2.jar;F:\Program Files\repository\io\vavr\vavr-match\0.10.2\vavr-match-0.10.2.jar;F:\Program Files\repository\io\github\resilience4j\resilience4j-core\1.3.0\resilience4j-core-1.3.0.jar;F:\Program Files\repository\com\fasterxml\jackson\core\jackson-annotations\2.13.4\jackson-annotations-2.13.4.jar;F:\Program Files\repository\com\fasterxml\jackson\core\jackson-core\2.13.4\jackson-core-2.13.4.jar;F:\Program Files\repository\com\esotericsoftware\kryo\5.5.0\kryo-5.5.0.jar;F:\Program Files\repository\com\esotericsoftware\reflectasm\1.11.9\reflectasm-1.11.9.jar;F:\Program Files\repository\com\esotericsoftware\minlog\1.3.1\minlog-1.3.1.jar;F:\Program Files\repository\com\tplink\smb\solution-components-lock-mem\1.3.4\solution-components-lock-mem-1.3.4.jar;F:\Program Files\repository\net\coobird\thumbnailator\0.4.20\thumbnailator-0.4.20.jar;F:\Program Files\repository\com\github\gotson\webp-imageio\0.2.2\webp-imageio-0.2.2.jar;F:\Program Files\repository\org\springframework\spring-test\5.2.12.RELEASE\spring-test-5.2.12.RELEASE.jar;F:\Program Files\repository\org\springframework\spring-core\5.3.25\spring-core-5.3.25.jar;F:\Program Files\repository\org\springframework\spring-jcl\5.3.25\spring-jcl-5.3.25.jar;F:\Program Files\repository\org\mockito\mockito-core\3.7.7\mockito-core-3.7.7.jar;F:\Program Files\repository\net\bytebuddy\byte-buddy\1.12.22\byte-buddy-1.12.22.jar;F:\Program Files\repository\net\bytebuddy\byte-buddy-agent\1.12.22\byte-buddy-agent-1.12.22.jar;F:\Program Files\repository\org\mockito\mockito-inline\3.7.7\mockito-inline-3.7.7.jar;F:\Program Files\repository\org\powermock\powermock-module-junit4\2.0.0\powermock-module-junit4-2.0.0.jar;F:\Program Files\repository\org\powermock\powermock-module-junit4-common\2.0.0\powermock-module-junit4-common-2.0.0.jar;F:\Program Files\repository\org\powermock\powermock-reflect\2.0.0\powermock-reflect-2.0.0.jar;F:\Program Files\repository\org\powermock\powermock-core\2.0.0\powermock-core-2.0.0.jar;F:\Program Files\repository\org\javassist\javassist\3.24.0-GA\javassist-3.24.0-GA.jar;F:\Program Files\repository\junit\junit\4.13.2\junit-4.13.2.jar;F:\Program Files\repository\org\hamcrest\hamcrest-core\2.2\hamcrest-core-2.2.jar;F:\Program Files\repository\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;F:\Program Files\repository\org\powermock\powermock-api-mockito2\2.0.0\powermock-api-mockito2-2.0.0.jar;F:\Program Files\repository\org\powermock\powermock-api-support\2.0.0\powermock-api-support-2.0.0.jar;F:\Program Files\repository\org\objenesis\objenesis\2.6\objenesis-2.6.jar&quot; com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.tplink.cdd.vms.person.core.domain.face.FaceImageUploadServiceTest,test2UploadEncryptedImageToS3_GeneralSecurityException org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced or misused argument matcher detected here: -&gt; at com.tplink.cdd.vms.person.core.domain.face.FaceImageUploadServiceTest.lambda$test2UploadEncryptedImageToS3_GeneralSecurityException$1(FaceImageUploadServiceTest.java:112) You cannot use argument matchers outside of verification or stubbing. Examples of correct usage of argument matchers: when(mock.get(anyInt())).thenReturn(null); doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject()); verify(mock).someMethod(contains(&quot;foo&quot;)) This message may appear after an NullPointerException if the last matcher is returning an object like any() but the stubbed method signature expect a primitive argument, in this case, use primitive alternatives. when(mock.get(any())); // bad use, will raise NPE when(mock.get(anyInt())); // correct usage use Also, this error might show up because you use argument matchers with methods that cannot be mocked. Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode(). Mocking methods declared on non-public parent classes is not supported. at com.tplink.cdd.vms.person.core.domain.face.FaceImageUploadServiceTest.test2UploadEncryptedImageToS3_GeneralSecurityException(FaceImageUploadServiceTest.java:112) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.mockito.internal.runners.DefaultInternalRunner$1$1.evaluate(DefaultInternalRunner.java:54) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.ParentRunner.run(ParentRunner.java:413) at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:99) at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:105) at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:40) at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55) 进程已结束,退出代码为 -1
最新发布
08-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值