テストが失敗した後、閉じる前にデバイスのスクリーンショットを撮る方法を探しています。
私が見つけた最も簡単な方法:
@Rule
public TestRule watcher = new TestWatcher() {
@Override
protected void failed(Throwable e, Description description) {
// Save to external storage (usually /sdcard/screenshots)
File path = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/screenshots/" + getTargetContext().getPackageName());
if (!path.exists()) {
path.mkdirs();
}
// Take advantage of UiAutomator screenshot method
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
String filename = description.getClassName() + "-" + description.getMethodName() + ".png";
device.takeScreenshot(new File(path, filename));
}
};
以前の回答に対する別の改善。私は実験的なものを使用しています スクリーンショットAPI
public class ScreenshotTestRule extends TestWatcher {
@Override
protected void failed(Throwable e, Description description) {
super.failed(e, description);
takeScreenshot(description);
}
private void takeScreenshot(Description description) {
String filename = description.getTestClass().getSimpleName() + "-" + description.getMethodName();
ScreenCapture capture = Screenshot.capture();
capture.setName(filename);
capture.setFormat(CompressFormat.PNG);
HashSet<ScreenCaptureProcessor> processors = new HashSet<>();
processors.add(new CustomScreenCaptureProcessor());
try {
capture.process(processors);
} catch (IOException e) {
e.printStackTrace();
}
}
}
BasicScreenCaptureProcessor が/ sdcard/Pictures /フォルダーを使用し、IOExceptionsが発生したため、CustomScreenCaptureProcessorを作成しましたフォルダ/イメージを作成するときのいくつかのデバイス。プロセッサを同じパッケージに入れる必要があることに注意してください
package Android.support.test.runner.screenshot;
public class CustomScreenCaptureProcessor extends BasicScreenCaptureProcessor {
public CustomScreenCaptureProcessor() {
super(
new File(
InstrumentationRegistry.getTargetContext().getExternalFilesDir(DIRECTORY_PICTURES),
"espresso_screenshots"
)
);
}
}
次に、ベースのEspressoテストクラスに追加するだけです
@Rule
public ScreenshotTestRule screenshotTestRule = new ScreenshotTestRule();
保護されたフォルダーを使用したい場合、これはエミュレーターでトリックを実行しましたが、物理デバイスでは機能しませんでした
@Rule
public RuleChain screenshotRule = RuleChain
.outerRule(GrantPermissionRule.grant(permission.WRITE_EXTERNAL_STORAGE))
.around(new ScreenshotTestRule());
Androidのテストではまだスクリーンショットを使用していませんが、役立つ可能性のあるいくつかの解決策を知っています。
そのための最良の方法は、Emma
またはSpoon
フレームワークを使用することです。
ここにそれを行う方法のいくつかの有用な情報があります: http://elekslabs.com/2014/05/creating-test-reports-for-Android-with-spoon-and-emma.html
Spoon
の公式Githubサイトもご覧ください: https://github.com/square/spoon およびそのGradleのプラグイン: https://github.com/stanfy/spoon -gradle-plugin
関連トピックを確認してください: SpoonにEspressoテストのスクリーンショットを撮らせる方法は?
このFacebookのライブラリを試すこともできます: https://facebook.github.io/screenshot-tests-for-Android/
すでに知っているように、Robotium
を使用すると、テストフレームワークでスクリーンショットを使用してテストを作成できます。チェック: RobotiumとCucumberでスクリーンショットを撮る正しい方法
ライブラリを使用したくない場合は、Robotium
フレームワーククラスのソースコードを確認してください ScreenshotTaker.Java
[リンクをクリックして表示]し、独自のScreenshotTaker
クラスを作成します。
それが役立つことを願っています。
説明されている他の回答のようにカスタムTestWatcherを作成するのが方法です。
[〜#〜] but [〜#〜](そしてそれに気付くのに長い時間がかかりました)警告があります:ルール- かもしれない発砲が遅すぎる、つまりあなたの活動がすでに破壊された後。これにより、失敗したアクティビティからではなく、デバイスのホーム画面のスクリーンショットが残ります。
RuleChain を使用してこれを解決できます:書く代わりに
@Rule
public final ActivityTestRule<MainActivity> _activityRule = new ActivityTestRule<>(MainActivity.class);
@Rule
public ScreenshotTestWatcher _screenshotWatcher = new ScreenshotTestWatcher();
あなたは書く必要があります:
private final ActivityTestRule<MainActivity> _activityRule = new ActivityTestRule<>(MainActivity.class);
@Rule
public final TestRule activityAndScreenshotRule = RuleChain
.outerRule(_activityRule)
.around(new ScreenshotTestWatcher());
これにより、最初にスクリーンショットが撮られ、次にアクティビティが破棄されます
@ Maragues Kotlinに移植された回答:
ヘルパークラス:
package utils
import Android.graphics.Bitmap
import Android.os.Environment.DIRECTORY_PICTURES
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.runner.screenshot.BasicScreenCaptureProcessor
import androidx.test.runner.screenshot.ScreenCaptureProcessor
import androidx.test.runner.screenshot.Screenshot
import org.junit.rules.TestWatcher
import org.junit.runner.Description
import Java.io.File
import Java.io.IOException
class IDTScreenCaptureProcessor : BasicScreenCaptureProcessor() {
init {
mTag = "IDTScreenCaptureProcessor"
mFileNameDelimiter = "-"
mDefaultFilenamePrefix = "Giorgos"
mDefaultScreenshotPath = getNewFilename()
}
private fun getNewFilename(): File? {
val context = getInstrumentation().getTargetContext().getApplicationContext()
return context.getExternalFilesDir(DIRECTORY_PICTURES)
}
}
class ScreenshotTestRule : TestWatcher() {
override fun finished(description: Description?) {
super.finished(description)
val className = description?.testClass?.simpleName ?: "NullClassname"
val methodName = description?.methodName ?: "NullMethodName"
val filename = "$className - $methodName"
val capture = Screenshot.capture()
capture.name = filename
capture.format = Bitmap.CompressFormat.PNG
val processors = HashSet<ScreenCaptureProcessor>()
processors.add(IDTScreenCaptureProcessor())
try {
capture.process(processors)
} catch (ioException: IOException) {
ioException.printStackTrace()
}
}
}
使用法:
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.rule.ActivityTestRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import utils.ScreenshotTestRule
@RunWith(AndroidJUnit4::class)
@LargeTest
class DialogActivityTest {
@get:Rule
val activityRule = ActivityTestRule(DialogActivity::class.Java)
@get:Rule
val screenshotTestRule = ScreenshotTestRule()
@Test
fun dialogLaunch_withTitleAndBody_displaysDialog() {
// setup
val title = "title"
val body = "body"
// assert
onView(withText(title)).check(matches(isCompletelyDisplayed()))
onView(withText(body)).check(matches(isCompletelyDisplayed()))
}
}
アプリのbuild.gradle
で宣言されたライブラリ:
androidTestImplementation "androidx.test.espresso:espresso-core:3.1.1"
androidTestImplementation "androidx.test.espresso:espresso-intents:3.1.1"
androidTestImplementation "androidx.test.ext:junit:1.1.0"
androidTestImplementation "androidx.test:runner:1.1.1"
androidTestImplementation "androidx.test:rules:1.1.1"
この設定では、毎回スクリーンショットが保存されますテストはフォルダーで終了します:/sdcard/Android/data/your.package.name/files/Pictures
Android Studioのデバイスファイルエクスプローラー(右側のサイドバー)
失敗したテストのスクリーンショットのみを保存する場合は、failed
ではなくTestWatcher
のfinished
メソッドをオーバーライドします。
this answerにいくつかの改善を加えました。 UiAutomatorに依存関係を追加する必要はなく、APIレベル18未満でも機能します。
public class ScreenshotTestWatcher extends TestWatcher
{
private static Activity currentActivity;
@Override
protected void failed(Throwable e, Description description)
{
Bitmap bitmap;
if (Android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)
{
bitmap = getInstrumentation().getUiAutomation().takeScreenshot();
}
else
{
// only in-app view-elements are visible.
bitmap = Screenshot.capture(getCurrentActivity()).getBitmap();
}
// Save to external storage '/storage/emulated/0/Android/data/[package name app]/cache/screenshots/'.
File folder = new File(getTargetContext().getExternalCacheDir().getAbsolutePath() + "/screenshots/");
if (!folder.exists())
{
folder.mkdirs();
}
storeBitmap(bitmap, folder.getPath() + "/" + getFileName(description));
}
private String getFileName(Description description)
{
String className = description.getClassName();
String methodName = description.getMethodName();
String dateTime = Calendar.getInstance().getTime().toString();
return className + "-" + methodName + "-" + dateTime + ".png";
}
private void storeBitmap(Bitmap bitmap, String path)
{
BufferedOutputStream out = null;
try
{
out = new BufferedOutputStream(new FileOutputStream(path));
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (out != null)
{
try
{
out.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
private static Activity getCurrentActivity()
{
getInstrumentation().runOnMainSync(new Runnable()
{
public void run()
{
Collection resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(
RESUMED);
if (resumedActivities.iterator().hasNext())
{
currentActivity = (Activity) resumedActivities.iterator().next();
}
}
});
return currentActivity;
}
}
次に、テストクラスに次の行を含めます。
@Rule
public TestRule watcher = new ScreenshotTestWatcher();