Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NoMatchingViewException leaks view hierarchies until test suite finishes #1661

Open
pyricau opened this issue Jan 23, 2023 · 5 comments
Open

Comments

@pyricau
Copy link
Contributor

pyricau commented Jan 23, 2023

Description

While a test suite is running, the AndroidJUnitRunner thread holds the test suite result in a local variable of type org.junit.runner.Result where Result.failures is a list of org.junit.runner.notification.Failure and each Failure has a Failure.fThrownException that points to the thrown exception, which here is a androidx.test.espresso.NoMatchingViewException. Unfortunately, NoMatchingViewException has a strong reference to the root view where the exception was thrown.

This means that while the test suite is running, any test failing due to a view matching error will leak to the corresponding root view being leaked for the duration of the test suite. This increases memory pressure. Developers who run LeakCanary in tests might see subsequent tests fail due to a leak being detected, when that leak is actually caused by the Espresso.

Steps to Reproduce

  • Run a test suite where the first test fails due to view matching
  • Add LeakCanary leak detection to a subsequent test, with a configuration to detect leaks in the whole heap dumps instead of just newly leaks in the current tests
  • Notice that subsequent tests fail as well.

Expected Results

  • Test infra should not hold on to view hierarchies of past tests, subsequent tests should not fail.

AndroidX Test and Android OS Versions

All versions of AndroidX Test and all versions of Android.

Link to a public git repo demonstrating the problem

square/leakcanary#2297

@ralf-at-android
Copy link
Collaborator

Hi,
We looked into it, and as you correctly pointed out in the description above, it looks like JUnit keeps references to all test failures and exceptions during the test run. So from an Espresso point of view, there's not much we can do here in the short term. Feel free to contribute a patch if you have a better way to handle this.

@TWiStErRob
Copy link
Contributor

It is possible to solve this by making NoMatchingViewException.rootView a WeakReference. The only usage of getRootView() is in a FailureHandler, which should run immediately-ish after an exception happens and at that time the activity should be still visible (therefore the weak reference would still be strong). After this rendering of the view hierarchy is done the rootView is just leaking as it is now. The WeakReference would take care of this by "forgetting" the rootView after it's not used. The getRootView is nullable anyway so there's no breaking change here IMO.

@pyricau
Copy link
Contributor Author

pyricau commented Jan 27, 2023

@ralf-at-android Would you be ok with the solution @TWiStErRob is describing? I do think it makes sense that you'd be able to access the view hierarchy as long as it's attached (i.e. essentially soon after the test fails) but once that UI is gone then Espresso should stop holding on to it.

To do this right, we'd probably need to also take care of the list of adapter views (=> List<WeakReference<View>>) and probably all the exceptions that implement RootViewException.

@darnmason
Copy link

Any development on this issue?

@rcgonzalezf
Copy link

It will be nice that now that 3.6.0 has been released to have this fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants