Skip to content

Instantly share code, notes, and snippets.

@jclarkin
Last active August 29, 2015 13:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jclarkin/5fe969ce98d4890c89dc to your computer and use it in GitHub Desktop.
Save jclarkin/5fe969ce98d4890c89dc to your computer and use it in GitHub Desktop.
Selenium (Java) Video recorder for JUnit4. Just add a @rule to your JUnit class and specify on which states to record (Pass, Fail, Error).
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import ScreenRecorderRule;
/**
* This is a sample test class that will output videos of Selenium WebDriver execution on Fail and
* Error results.
*/
@RunWith( JUnit4.class )
public class CreateAdHocTaskExample
{
@Rule public ScreenRecorderRule iRule = new ScreenRecorderRule( false, true, true );
/**
* This is a sample test case
*/
@Test public void testCreateAdHocTask()
{
Assert.fail( "Not yet implemented" );
}
}
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* JUnit Rule to record the test execution to an AVI file, depending on the test result status
* (success, fail, or error)
*
* @author jclarkin
*/
public class ScreenRecorderRule
implements TestRule
{
private final boolean iRecordError;
private final boolean iRecordFailure;
private final boolean iRecordSuccess;
/**
* Creates a new {@linkplain ScreenRecorderRule} object.
*
* @param aRecordSuccess If true, will record test on success
* @param aRecordFailure If true, will record test on failure
* @param aRecordError If true, will record test on error
*/
public ScreenRecorderRule( boolean aRecordSuccess, boolean aRecordFailure,
boolean aRecordError
)
{
super();
this.iRecordSuccess = aRecordSuccess;
this.iRecordFailure = aRecordFailure;
this.iRecordError = aRecordError;
}
/**
* {@inheritDoc}
*/
@Override public Statement apply( Statement aBase, Description aDescription )
{
String lFilename = aDescription.getClassName() + "." + aDescription.getMethodName();
return new ScreenRecorderStatement(
aBase,
lFilename,
iRecordSuccess,
iRecordFailure,
iRecordError
);
}
/**
* Handles execution of test and potentially records the execution as well
*/
public class ScreenRecorderStatement
extends Statement
{
private final Statement iBase;
private final String iFilename;
private final boolean iRecordError;
private final boolean iRecordFailure;
private final boolean iRecordSuccess;
/**
* Creates a new {@linkplain ScreenRecorderStatement} object.
*
* @param aBase The base test statement
* @param aFilename The prefix to use for the recording file name
* @param aRecordSuccess If true, will record test on success
* @param aRecordFailure If true, will record test on failure
* @param aRecordError If true, will record test on error
*/
public ScreenRecorderStatement(
Statement aBase,
String aFilename,
boolean aRecordSuccess,
boolean aRecordFailure,
boolean aRecordError
)
{
this.iRecordSuccess = aRecordSuccess;
this.iRecordFailure = aRecordFailure;
this.iRecordError = aRecordError;
this.iBase = aBase;
this.iFilename = aFilename;
}
/**
* Executes the test and saves a recording depending on the test result status
*
* @throws Throwable If an error or failure occurs
*/
@Override public void evaluate()
throws Throwable
{
TestRecorder lRecorder = new TestRecorder( iFilename );
boolean lSucceeded = false;
boolean lFailed = false;
boolean lError = false;
try {
lRecorder.start();
iBase.evaluate();
lSucceeded = true;
} catch ( Throwable e ) {
if ( e instanceof AssertionError ) {
lFailed = true;
} else {
lError = true;
}
throw e;
} finally {
lRecorder.stop();
boolean lKeepFile =
( lSucceeded && iRecordSuccess ) || ( lFailed && iRecordFailure ) ||
( lError && iRecordError );
// If not keeping the file, delete it
if ( !lKeepFile ) {
lRecorder.delete();
}
}
}
}
}
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.monte.media.Format;
import org.monte.media.FormatKeys.MediaType;
import org.monte.media.Registry;
import static org.monte.media.VideoFormatKeys.*;
import org.monte.media.math.Rational;
import org.monte.screenrecorder.ScreenRecorder;
import java.awt.AWTException;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
/**
* A customized instance of the ScreenRecorder that allows the filename prefix to be specified, as
* well as functionality to delete the recording
*/
public class TestRecorder
extends ScreenRecorder
{
private String iFilename;
private File iMovieFile;
/**
* Creates a new {@linkplain TestRecorder} object.
*
* @param aFilename The Prefix filename to use
*
* @throws IOException If an error occurs with saving the recording
* @throws AWTException If an error occurs in accessing the video screen
*/
public TestRecorder( String aFilename )
throws IOException, AWTException
{
super( buildConfig(), buildFileFormat(), buildScreenFormat(), buildMouseFormat(), null );
iFilename = aFilename;
}
/**
* Delete the recorded file
*
* @return True if succeeded to delete
*/
public boolean delete()
{
boolean lDeleted = false;
if ( State.DONE == this.getState() ) {
lDeleted = iMovieFile.delete();
}
return lDeleted;
}
/**
* {@inheritDoc}
*/
@Override protected File createMovieFile( Format aFileFormat )
throws IOException
{
if ( !movieFolder.exists() ) {
movieFolder.mkdirs();
} else if ( !movieFolder.isDirectory() ) {
throw new IOException( "\"" + movieFolder + "\" is not a directory." );
}
SimpleDateFormat lDateFormat = new SimpleDateFormat( "yyyy-MM-dd 'at' HH.mm.ss" );
iMovieFile =
new File(
movieFolder, //
iFilename + " " + lDateFormat.format( new Date() ) + "." +
Registry.getInstance().getExtension( aFileFormat )
);
return iMovieFile;
}
/**
* Generate the Graphics configuration used to access the video screen
*
* @return Graphics configuration
*/
private static GraphicsConfiguration buildConfig()
{
return GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration();
}
/**
* Generate the fileformat for the recording to be saved
*
* @return The fileformat of the recording
*/
private static Format buildFileFormat()
{
return new Format( MediaTypeKey, MediaType.FILE, MimeTypeKey, MIME_AVI );
}
/**
* Generate the Mouse accessor details for recording
*
* @return Mouse accessor configuration
*/
private static Format buildMouseFormat()
{
return new Format(
MediaTypeKey,
MediaType.VIDEO,
EncodingKey,
"black",
FrameRateKey,
Rational.valueOf( 30 )
);
}
/**
* Generate the Screen accessor details for recording
*
* @return Screen accessor configuration
*/
private static Format buildScreenFormat()
{
return new Format(
MediaTypeKey,
MediaType.VIDEO,
EncodingKey,
ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,
CompressorNameKey,
ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,
DepthKey,
24,
FrameRateKey,
Rational.valueOf( 15 ),
QualityKey,
1.0f,
KeyFrameIntervalKey,
15 * 60
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment