Parallel testing with cucumber and Gradle - java

I keep finding posts and articles on how to run parallel tests with Cucumber and Maven, but nothing with Gradle.
I have the following scenario:
Scenario Outline: Author from API matches author on book page
Given user goes on google.com
when user search <item>
and click on <locator>
Then something happens
Examples:
| item | locator |
| item1 | locator1|
| item2 | locator2|
| item3 | locator3|
Is it possible, with Gradle, to run this scenario in parallel, each execution using the values in "Examples" table?
Thanks

It is possible! But you have to apply some workarounds.
plugins {
java
}
dependencies {
testImplementation(platform("org.junit:junit-bom:5.9.2"))
testImplementation(platform("io.cucumber:cucumber-bom:7.11.1"))
testImplementation("io.cucumber:cucumber-java")
testImplementation("io.cucumber:cucumber-junit-platform-engine")
testImplementation("org.junit.platform:junit-platform-suite")
testImplementation("org.junit.jupiter:junit-jupiter")
}
repositories {
mavenLocal()
mavenCentral()
}
tasks.withType<Test> {
useJUnitPlatform()
// Work around. Gradle does not include enough information to disambiguate
// between different examples and scenarios.
systemProperty("cucumber.junit-platform.naming-strategy", "long")
}
Because Gradle provides rather limited support for tests that aren't a in class file you have to use the junit-platform-suite to declare a suite.
package io.cucumber.skeleton;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
#Suite
#IncludeEngines("cucumber")
#SelectClasspathResource("io/cucumber/skeleton")
#ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "io.cucumber.skeleton")
public class RunCucumberTest {
}
This suite will target the cucumber TestEngine from cucumber-junit-platform-engine. The cucumber-java-skeleton contains a working (serial) example.
To make the tests execute in parallel you can add to junit-platform.properties:
cucumber.execution.parallel.enabled=true
That is it. For more config details check the JUnit 5 and Cucumber JUnit Platform Engine documentation.

Related

Windows, Gradle and Cucumber combination throws an IOException upon generating reports

I'm working on a project which uses a combination of Windows, Java, Groovy, Gradle and Cucumber. This combination gives me some problems on my Windows machine that my *NIX colleagues are not experiencing. Upon running the gradle build, gradle wants to output some reports. The location and filename of these reports is apparently determined by the definition or output of the Cucumber tests. The name used is unfortunately not something that can be used as a filename, so I'm getting an IOException for each test report.
For the Cucumber test, we use the following structure:
Scenario Outline: Receive and parse ReturnItem from Service
Given The message from service return item outlined in <messagePath>
When We process the message
Then XXX posted a message to YYY on topic <topic> with event <eventType>
And payload matches <resultPath>
| messagePath | topic | eventType | resultPath |
| /test/testxml.xml | test_topic | EVENT_TYPE | /result/result.json |
After running this, I receive the following exception:
Caused by: org.gradle.api.UncheckedIOException: Could not write to file 'C:\xxx\project\build\reports\tests\test\packages\| \test\testxml.xml | test_topic | EVENT_TYPE | \result\result.html'.
at org.gradle.internal.IoActions$TextFileWriterIoAction.execute(IoActions.java:151)
at org.gradle.internal.IoActions$TextFileWriterIoAction.execute(IoActions.java:127)
at org.gradle.internal.IoActions.writeTextFile(IoActions.java:45)
at org.gradle.reporting.HtmlReportRenderer$DefaultHtmlReportContext.renderHtmlPage(HtmlReportRenderer.java:118)
at org.gradle.api.internal.tasks.testing.report.DefaultTestReport$HtmlReportFileGenerator.run(DefaultTestReport.java:147)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:300)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:292)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:174)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.access$900(DefaultBuildOperationExecutor.java:48)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$ParentPreservingQueueWorker.execute(DefaultBuildOperationExecutor.java:342)
at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperation(DefaultBuildOperationQueue.java:230)
at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.access$600(DefaultBuildOperationQueue.java:172)
at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable$1.call(DefaultBuildOperationQueue.java:209)
at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable$1.call(DefaultBuildOperationQueue.java:203)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:154)
at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatch(DefaultBuildOperationQueue.java:203)
at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.run(DefaultBuildOperationQueue.java:177)
... 3 more
Caused by: java.io.IOException: Unable to create directory 'C:\xxx\project\project-test\build\reports\tests\test\packages\| \test\testxml.xml | test_topic | EVENT_TYPE | \result'
at org.gradle.internal.IoActions$TextFileWriterIoAction.execute(IoActions.java:141)
... 19 more
Does anybody know how to fix this? The only 'solution' I could come up with is disabling the reports, which works, but is more a workaround than a solution. For disabling I used the following configuration in the gradle.build for this:
apply plugin: 'java'
apply plugin: 'groovy'
test {
reports {
junitXml.enabled = false
html.enabled = false
}
}
(Inspired by: How to make Gradle build produce HTML test report instead of XML default?)
I finally found the culprit. Apparently these filenames correspond to the default behaviour of JUnit for report generation of Cucumber tests. On *NIX, this doesn't provide any problem. On Windows however, this will result in an exception due to the pipes in the Examples. The IOException is somewhat special apparently, since the most exceptions that I found on the internet were FileNotFoundExceptions. That explains why it took me so long to find an answer, I focused on the exception.
The solution here is to use the following JUnitOption as an #CucumberOptions annotation when running the Cucumber tests: --filename-compatible-names.
A code example for Java & Spring looks like this:
#RunWith(Cucumber.class)
#CucumberOptions(junit = {"--filename-compatible-names"})
public class CucumberRunner {
}
It would be nice if these kind of non-breaking OS dependent options would be default instead of optional.
Based upon the information provided, it looks like it's trying to create a directory called:
'C:\xxx\project\project-test\build\reports\tests\test\packages\| \test\testxml.xml | test_topic | EVENT_TYPE | \result'
Can you show the code around passing in messagePath? I suspect you are passing in the entire row of data rather than just the messagePath (I'm going to take a wild guess that you are performing a .toString() on an array instead of passing in the first element of the array)

Running the same Gradle task multiple times

So i have a gradle test task which runs all my tests. How can I set up gradle to run this task 100 times? It works and runs all my tests, I just need an option to choose how many times to run this.
The task in build.gradle:
test {
// enable JUnit Platform (a.k.a. JUnit 5) support
useJUnitPlatform()
// set a system property for the test JVM(s)
systemProperty 'some.prop', 'value'
// explicitly include or exclude tests
include 'com/company/calculator/**'
// show standard out and standard error of the test JVM(s) on the console
testLogging.showStandardStreams = true
// set heap size for the test JVM(s)
minHeapSize = "128m"
maxHeapSize = "512m"
// set JVM arguments for the test JVM(s)
jvmArgs '-XX:MaxPermSize=256m'
// listen to events in the test execution lifecycle
beforeTest { descriptor ->
logger.lifecycle("Running test: " + descriptor)
}
// Fail the 'test' task on the first test failure
failFast = true
// listen to standard out and standard error of the test JVM(s)
onOutput { descriptor, event ->
logger.lifecycle("Test: " + descriptor + " produced standard out/err: " + event.message )
}
The use case is that i want to test performance of different assertions and mocking libraries (i have multiple branches with tests written using different libraries), to do that i need to run test suite multiple times.
To test performance i need to measure the time it takes to run these tests for example 100 times (maybe 1000), on each libraries set.
One option might be this --rerun-tasks flag.
gradle test --rerun-tasks
From the Gradle user guide.
Another option, from a similar question, is creating a subclass of the Test class that returns a task with multiple copies of all tests, code here: https://stackoverflow.com/a/41650455/1686615 .
There really are many ways to do this at different levels, with Gradle code as in that link, or perhaps in .gradle files, with a parameter passed into the test code, or on the command line. Maybe indicate more about your use case or if there is a particular level at which you'd like to make the change.

Perform some high-level operation of Unit test finish?

Is it possible to perform some high-level operation at Unit testing end?
Like grabbing all test results and logs and sending them by email to developer?
Would like solution either in JUnit or with Gradle.
A pure JUnit approach could be to implement your own RunListener to be able to grab the information of each of your tests.
To invoke your listener, you need to run your tests through JUnitCore.
public void main(String... args) {
JUnitCore core= new JUnitCore();
core.addListener(new MyRunListener());
core.run(MyTestClass.class);
}
A pure Gradle approach could be to implement your own TestListener to be able to grab the information of each of your tests and send the final report.
In build.gradle you will need to add gradle.addListener(new my.package.MyTestListener()). Your listener must be in the build source directory also known as buildSrc.
test.finalizedBy(someHighLevelOperationTask)
Example: Here is a task that you can call gradle emailTestResults that would depend on 'zipTestResults' which depends on test. I have not done the email part of it, there's a question that covers that: Sending email using Gradle
So this just spits out a println in place of the email task:
apply plugin: 'java'
task zipTestResults(dependsOn: 'test', type: Zip){
from 'build/reports/tests'
baseName 'TestReport'
destinationDir file('build/reports')
}
task emailTestResults(dependsOn: 'zipTestResults') << {
println 'Emailing...' + file('build/reports/TestReport.zip')
}
repositories{
jcenter()
}
dependencies{
testCompile 'junit:junit:4.12'
}
But that won't work if the test fails, so, there maybe a better way, but you can add this:
test.ignoreFailures = true
Then if you then always want to email the test results add:
test.finalizedBy(emailTestResults)
Then a gradle test would finish by emailing the results.

Unit testing creating an SQLite database using Spock and Robospock

spock-core:0.7-groovy-2.0
robospock:0.5.0
Android Studio 0.8.2
Fedora release 20 (Heisenbug)
This is the complete solution. Now it compiles and runs the unit test successfully, and the directory structure is the same as the preview edit. Please feel free to comment on anything that doesn't look right.
Edit Solution =====
build.gradle:
apply plugin: 'java'
apply plugin: 'groovy'
repositories {
mavenCentral()
maven {
// Location of Android SDK for compiling otherwise get this error:
/* Could not find com.android.support:support-v4:19.0.1.
Required by:
:testSQLite:unspecified > org.robospock:robospock:0.5.0 > org.robolectric:robolectric:2.3 */
url "/home/steve/local/android-studio/sdk/extras/android/m2repository/"
}
}
dependencies {
// just compile so we can use the sqlite API
compile 'com.google.android:android:4.1.1.4', {
// Do not bring in dependencies
transitive = false
}
testCompile 'org.codehaus.groovy:groovy:2.3.+'
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
testCompile 'org.robospock:robospock:0.5.0'
testCompile 'org.robospock:robospock-plugin:0.4.0'
}
SnapzClientTest.groovy:
package com.example.DataAccess
import com.example.DataAccess.SnapzAndroidDB
import org.robolectric.Robolectric
import pl.polidea.robospock.RoboSpecification
class SnapClientTest extends RoboSpecification {
/* Create Sqlite database for Android */
def 'Create a sqlite database for Android'() {
setup:
def androidDB = new SnapzAndroidDB(Robolectric.application)
expect:
androidDB != null
}
}
SnapzAndroidDB.java, no change from the 5th August Edit
Edit 5 August ================
Basically, I am trying to create a JAR file that will be used in an Android app that will have the functionality of SQLite, so I can use this JAR file for many apps.
I have started from scratch and created a smaller application that is easier to bug fix. This is the directory structure, and there is only three files:
testSQLite/build.gradle
testSQLite/src/main/java/com/example/sqltest/SnapzAndroidDB.java
testSQLite/src/test/groovy/SnapzClientTest.groovy
build.gradle
apply plugin: 'java'
apply plugin: 'groovy'
repositories {
mavenCentral()
maven {
// Location of Android SDK for compiling otherwise get this error:
/* Could not find com.android.support:support-v4:19.0.1.
Required by:
:testSQLite:unspecified > org.robospock:robospock:0.5.0 > org.robolectric:robolectric:2.3 */
url "/home/steve/local/android-studio/sdk/extras/android/m2repository/"
}
}
dependencies {
// Just compile so we can use the sqlite API
compile 'com.google.android:android:4.1.1.4', {
// Do not bring in dependencies
transitive = false
}
testCompile 'org.codehaus.groovy:groovy:2.3.+'
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
testCompile 'org.robospock:robospock:0.5.0'
testCompile 'org.robospock:robospock-plugin:0.4.0'
}
SnapzAndroidDB.java
package com.example.DataAccess;
import java.util.logging.ConsoleHandler;
import java.util.logging.SimpleFormatter;
import java.util.logging.Handler;
import java.util.logging.Logger;
import java.util.logging.Level;
import android.content.Context;
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteException;
import android.database.Cursor;
public class SnapzAndroidDB extends SQLiteOpenHelper {
/**
* Logger for displaying log messages
*/
private static final Logger log = Logger.getLogger("SnapzAndroidDB");
private SQLiteDatabase mDb;
public SnapzAndroidDB(Context context) {
super(context, "DB_NAME", null, 1);
/* Create logger */
ConsoleHandler consoleHandler = new ConsoleHandler();
log.addHandler(consoleHandler);
log.setLevel(Level.FINE);
consoleHandler.setFormatter(new SimpleFormatter());
consoleHandler.setLevel(Level.ALL);
log.log(Level.INFO, "SnapzAndroidDB()");
}
/* Called only once first time the database is created */
#Override
public void onCreate(SQLiteDatabase mDb) {
log.log(Level.INFO, "onCreate(SQLiteDatabase db)");
String createConfig = String.format("create table %s (%s int primary key, %s text, %s text)",
"TABLE_CONFIG",
"ID",
"NAME",
"VALUE");
log.log(Level.INFO, "onCreate with SQL: " + createConfig);
mDb.execSQL(createConfig);
}
#Override
public void onUpgrade(SQLiteDatabase mDb, int oldVersion, int newVersion) {
log.log(Level.INFO, "onUpgrade()");
/* Only if there is some schema changes to the database */
}
}
SnapzClientTest.groovy
package com.example.DataAccess
import com.example.DataAccess.SnapzAndroidDB
import spock.lang.Specification
import org.robolectric.Robolectric
class SnapClientTest extends Specification {
/* Create SQLite database for Android */
def 'Create an SQLite database for Android'() {
setup:
def androidDB = new SnapzAndroidDB(Robolectric.application)
expect:
androidDB != null
}
}
The error I am still getting is the following:
com.example.DataAccess.SnapClientTest > Create an SQLite database for Android FAILED
java.lang.RuntimeException: Stub!
at android.database.sqlite.SQLiteOpenHelper.<init>(SQLiteOpenHelper.java:4)
at com.example.DataAccess.SnapzAndroidDB.<init>(SnapzAndroidDB.java:26)
at com.example.DataAccess.SnapClientTest.Create a sqlite database for Android(SnapzClientTest.groovy:15)
Edit 4 August ===================
This is my updated test specification that uses Robolectric to generate a context that can be used in the constructor of SQLiteOpenHelper(...)
import org.robolectric.Robolectric
def 'Create an SQLite database for Android'() {
setup:
def androidDB = new SnapzAndroidDB(Robolectric.application)
expect:
androidDB != null
}
The function I am actually testing is a class that extends SQLiteOpenHelper. And my constructor SnapzAndroidDB(...) calls SQLiteOpenHelper() constructor, as you can see the context is the first parameter that is passed from the test spec:
public class SnapzAndroidDB extends SQLiteOpenHelper
public SnapzAndroidDB(Context context) {
super(context, SnapzContract.DB_NAME, null, SnapzContract.DB_VERSION);
}
.
.
}
When I run my test I get this error:
com.sunsystem.HttpSnapClient.SnapClientTest > Create an SQLite database for Android FAILED
java.lang.RuntimeException: Stub!
at android.database.sqlite.SQLiteOpenHelper.<init>(SQLiteOpenHelper.java:4)
at com.sunsystem.DataAccess.SnapzAndroidDB.<init>(SnapzAndroidDB.java:33)
at com.sunsystem.HttpSnapClient.SnapClientTest.Create a sqlite database for Android(SnapClientTest.groovy:168)
END EDIT =======================
Edit ====
When I try and use the getBaseContext() I get the following error:
com.sunsystem.HttpSnapClient.SnapClientTest > Create an SQLite database for Android FAILED
groovy.lang.MissingMethodException: No signature of method: com.sunsystem.HttpSnapClient.SnapClientTest.getBaseContext() is applicable for argument types: () values: []
at com.sunsystem.HttpSnapClient.SnapClientTest.Create a sqlite database for Android(SnapClientTest.groovy:159)
My specification spock function is this:
def 'Create an SQLite database for Android'() {
setup:
def androidDB = new SnapzAndroidDB(getBaseContext())
expect:
androidDB != null
}
Here are the dependencies:
dependencies {
compile "com.googlecode.json-simple:json-simple:1.1.1", {
// Exclude junit as we don't want this include in our JAR file as it will add hamcast and other dependencies as well
exclude group:'junit', module: 'junit'
}
// Just compile so we can use the SQLite API. This won't be included in the JAR
compile 'com.google.android:android:4.1.1.4', {
// Do not bring in dependencies
transitive = false
}
// Compile for unit testing only
testCompile "org.codehaus.groovy:groovy:2.3.4"
testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
testCompile 'org.robospock:robospock:0.5.0'
testCompile 'com.google.android:android-test:4.1.1.4'
testCompile 'com.android.tools.build:gradle:0.12.2'
testCompile 'org.robospock:robospock-plugin:0.4.0'
}
====
I am doing Spock unit testing for my library written in Java that will be used in my Android application.
The Java JAR file that will be deployed to an Android application for doing database stuff. It's this JAR file I am testing.
I have written a Spock specification for testing the creation of an SQLite database.
In my Java JAR file I have a class that creates the SQLite database, and I want to test that in my Spock unit test.
However, the problem is that the SQLiteOpenHelper constructor needs to be called with a Context, and I am trying to mock that context using import android.text.mock.MockContext in my Spock unit test.
public class SnapzAndroidDB extends SQLiteOpenHelper implements SnapzDAO {
public SnapzAndroidDB(Context context) {
super(context, SnapzContract.DB_NAME, null, SnapzContract.DB_VERSION);
}
/* Called only once first time the database is created */
#Override
public void onCreate(SQLiteDatabase db) {
String sqlCreate = String.format("create table %s (%s int primary key, %s text, %s text, %s text)",
SnapzContract.TABLE,
SnapzContract.GetConfigColumn.ID,
SnapzContract.GetConfigColumn.NAME,
SnapzContract.GetConfigColumn.VALUE,
SnapzContract.GetConfigColumn.CFG_TYPE);
db.execSQL(sqlCreate);
}
.
.
}
Now in my unit testing spec I have this in my SnapClientTest.groovy:
import android.test.mock.MockContext
def 'Create an SQLite database for Android'() {
setup:
def context = new MockContext()
def androidDB = new SnapzAndroidDB(context.getApplicationContext())
expect:
androidDB != null
}
From this you can see that I am mocking the context and sending that as a parameter to the constructor of my class that will call the SQLiteOpenHelper constructor.
The error I get when I run my unit test is this:
com.HttpSnapClient.SnapClientTest > Create an SQLite database for Android FAILED
11:05:27.062 [DEBUG] [TestEventLogger] java.lang.RuntimeException: Stub!
11:05:27.063 [DEBUG] [TestEventLogger] at android.content.Context.<init>(Context.java:4)
11:05:27.063 [DEBUG] [TestEventLogger] at android.test.mock.MockContext.<init>(MockContext.java:5)
11:05:27.063 [DEBUG] [TestEventLogger] at com.sunsystem.HttpSnapClient.SnapClientTest.Create a sqlite database for Android(SnapClientTest.groovy:155)
11:05:27.065 [QUIET] [system.out] 11:05:27.064 [DEBUG] [org.gradle.process.internal.child.ActionExecutionWorker] Stopping client connection.
Being new to Spock I am not sure if this is possible or not, as I am just testing my JAR file.
Spock is one of the most widely used frameworks in the Groovy and Java ecosystem that allows the creation of BDD tests in a very intuitive language and facilitates some common tasks such as mocking and extensibility. What makes it stand out from the crowd is its beautiful and highly expressive specification language. Thanks to its JUnit runner, Spock is compatible with most IDEs, build tools, and continuous integration servers. To work with Spock you basically need to perform a set of steps, such as following a recipe, that will allow you to effectively implement both a unit test and a web integration.
Your current error message reads:
Create a sqlite database for Android FAILED
Try these steps and see how it goes:
Including to your code getWritableDatabase and getReadableDatabase should help:
jokesHelper dbHelper = new jokesHelper(getBaseContext());
SQLiteDatabase db = dbHelper.getWritableDatabase();
Doing so, Android will be able manage and cache the connection.
Yet if you got any error message from getBaseContext, try to uninstall the testing plugin and recreate the STS resources (.classpath & .project) using integrate-with --eclipse, then it should work.
If you are having any problem with getSpecificationContext, it means that some detail was left out and you need to double check your specifications.
In case you are not using Eclipse, to create your Java Jar file with spock, you can interface it with Emacs through command-line Java development tools as usual, for instance Sun’s JDK or any other approach expected for Enterprise Development. To only run a SampleTest you must invoke the test task from the command-line with the Java system property:
gradle -Dtest.single=Sample test
Or alternatively
gradle -Dtest.single=SoapTest clean test
Also check what are the permissions on the directory in use. And in case you haven't done yet, remember to include dependencies:
dependencies {
classpath 'com.android.tools.build:gradle:0.8.+'
classpath 'org.robospock:robospock-plugin:0.4.0'
}
And inform the test directory that you are using, e.g. srcDirs. And keep in mind that ("Es ist wichtig das man hier die richtige Resources-Klasse importiert") it is important to import the right resource required by the class. As such, also include to "build.gradle" in the "defaultConfig":
testPackageName "com.yourpackage.test"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
testFunctionalTest true
The Spock and Robospock are innovative tools that can aid helpful resources for development of unit test. Alternatively you could also use tools such as TCL Tests. The TCL Tests are the oldest set of tests for SQLite and is the best approach you can take. In fact, SQLite started life as a Tcl extension. Much of the testing and development tools for SQLite are written in Tcl. In addition to the native C API, the Tcl extension is the only API supported by the core SQLite team.
To enable the Tcl bindings, download the TEA (Tcl Extension Architecture) distribution of the SQLite source from the SQLite website. This version of the code is essentially the amalgamation distribution with the
Tcl bindings appended to the end. This will build into a Tcl extension that can then be imported into any Tcl environment.
Very specific steps should be followed and attention to every single detail is essential, as it can make the difference to enable your testing to successfully run or not.
The instrumentation framework is the foundation of the testing framework.
Instrumentation controls the application under test and permits the injection of mock components required by the application to run. For example, you can create mock Contexts before the application starts and let the application use them.
All interaction of the application with the surrounding environment can be controlled using this approach. You can also isolate your application in a restricted environment to be able to predict the results, forcing the values returned by some methods or mocking persistent and unchanged data for ContentProvider, databases, or even the filesystem content. Therefore, it is also important to specify in your activity the information that you are running a test:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.aatg.sample.test"
android:versionCode="1" android:versionName="1.0">
<application android:icon="#drawable/icon"
android:label="#string/app_name">
<uses-library android:name="android.test.runner" />
</application>
<uses-sdk android:minSdkVersion="7" />
<instrumentation
android:targetPackage="com.example.aatg.sample
android:name="android.test.InstrumentationTestRunner"
android:label="Sample Tests" />
<uses-permission android:name="
android.permission.INJECT_EVENTS" />
</manifest>
In case you run JNI to manipulate your database with native code, there are two ways to load an extension with SQLite. One is through a C API call, and one is through an SQL function that calls down into the same code as the C API function. In both cases, you provide a filename and, optionally, the name of the entry point function:
int sqlite3_load_extension( sqlite3 *db, const char *ext_name,
const char *entry_point, char **error )
The other way to load a loadable extension is with the built-in SQL function:
load_extension( 'ext_name' )
load_extension( 'ext_name', 'entry_point' )
This function is similar to the C sqlite3_load_extension() call, with one major limitation. Because this is an SQL function, when it is called there will be, by definition, an SQL statement executing when the extension is loaded. That means that any extension loaded with the load_extension() SQL function will be completely unable to redefine
or delete a custom function, including the specialized set of like() functions. Approaches to load the data with suitable syntax works similarly with Java, as expected.
Debug directives are only used for testing and development
purposes, as they add significant overhead and make everything run noticeably slower, just similarly as to including throws Exception. As you are running unit test you need to set them accordingly, and also check to avoid that you database don't get corrupted. Basically, achieving the best tune for your debugging settings will improve and help you go smoothly to put your testing to run in the best way.
In addition to all the other build directives, SQLite has a fair number of SQLITE_OMIT_* compile-time directives. These are designed to remove core features from the build in an effort to make the core database library as small and compact as possible. In order to use most of these omit directives, you need to be building SQLite from the development sources found in the source control tree. Most omit directives won’t work
correctly when applied to a source distribution or to the pre-built amalgamation. Also be aware that these compile-time directives are not officially supported, in the sense that they are not part of the official testing chain. For any given version of SQLite, there may be both compile problems and runtime issues if arbitrary sets of omit flags are enabled.
Of course you don't need to be a samurai to run unit test for SQLite on Android, although it might help.
The issue you are facing is getting a correct Context for creating the DB.
Your first attempt with getBaseContext() didn't work since it didn't find a function like that in SnapClientTest: "No signature of method"
In your second attempt you are creating an Instance of MockContext - this is a stub implementation that you can't use directly.
http://developer.android.com/reference/android/test/mock/MockContext.html
"A mock Context class. All methods are non-functional and throw UnsupportedOperationException."
Try:
def androidDB = new SnapzAndroidDB(Robolectric.application)
Accoding to http://robospock.org/ Robolectric.application should give a working context.
Update
I just noticed you are not extending RoboSpecification but Specification:
import pl.polidea.robospock.RoboSpecification
and
class SnapClientTest extends RoboSpecification

Excluding a a folder from test runs with TestNG and Gradle

I'm trying to exclude a 'quarantine' folder that I set up for Selenium tests that need to be updated and I do not wish to have run. I know that one solution is to set up and assign test groups for the tests in these classes but given the sheer size and volume of tests that will be in here, I'd rather do it using an Ant-style filter.
Here is a snippet of my build.gradle file:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'
repositories {
mavenCentral()
}
dependencies {
compile "org.seleniumhq.selenium:selenium-java:2.35.0"
compile "org.testng:testng:5.14.10"
testCompile('org.uncommons:reportng:1.1.2') {
exclude group: 'org.testng'
}
testCompile "junit:junit:4.8.2"
compile "com.jayway.restassured:rest-assured:1.8.1"
}
//initialize thread count variable for parallel testing and default to 1
def threadCount = System.getProperty("MAXTHREADS", "1")
tasks.withType(Test) {
maxParallelForks = 1
forkEvery = 1000
ignoreFailures = false
// Pass all system properties to the tests
systemProperties = System.getProperties()
// Makes the standard streams (err and out) visible at console when running tests
testLogging.showStandardStreams = true
exclude '**/tasks/'
exclude '**/disabled/'
classpath += configurations.testCompile
}
task firefox(type: Test) {
maxParallelForks = Integer.valueOf(threadCount) //default is 1 if not specified
testLogging.events "started"
testLogging {
events "started", "passed", "skipped", "failed", "standardOut", "standardError"
exceptionFormat "full" // default is "short"
}
useTestNG() {
excludeGroups 'chrome'
useDefaultListeners = false
listeners << 'org.uncommons.reportng.HTMLReporter'
listeners << 'org.uncommons.reportng.JUnitXMLReporter'
listeners << 'com.xmatters.testng.Listener'
}
testResultsDir = file("${buildDir}/test-results/firefox")
testReportDir = file("${reporting.baseDir}/firefox")
systemProperties.BROWSER = System.getProperty('BROWSER', 'firefox')
exclude '**/selenium/'
exclude '**/setupscripts/'
}
task chrome(type: Test) {
maxParallelForks = Integer.valueOf(threadCount) //default is 1 if not specified
testLogging.events "started"
useTestNG() {
useDefaultListeners = false;
listeners << 'org.uncommons.reportng.HTMLReporter'
listeners << 'org.uncommons.reportng.JUnitXMLReporter'
listeners << 'com.xmatters.testng.Listener'
}
testResultsDir = file("${buildDir}/test-results/chrome")
testReportDir = file("${reporting.baseDir}/chrome")
systemProperties.BROWSER = System.getProperty('BROWSER', 'chrome')
exclude '**/selenium/'
exclude '**/setupscripts/'
}
On line 34 you can see exclude '**/disabled/' that I added. This folder is a couple levels up from the root folder. The preceding like with exclude '**/tasks/' was already in the build file and seems to work fine with a similar directory structure.
When I run the build, tests in the /disabled/ folder are still getting run. Is there something I'm doing wrong here? I'm assuming that with that syntax, a directory named 'exclude' a couple levels up would be ignored by scanForTestClasses which is true by default. Any idea what is up here?
One other thing I've noticed in Gradle test report is that the package name listed in the report is default-packagefor the excluded tests that are not 'excluding' whereas the other tests that are meant to be run are listing the correct package names. The package names in the Java files match their folder structure correctly so I'm not sure why this is being reported this way. I've checked for duplicates, typos, etc, and am not getting anywhere.
If anyone could shed some light on this that would be great as having these incomplete / broken test classes running is causing failures that should be ignored until these tests are updated.
These test are being run using the Gradle wrapper generated bash script on our test CI (Jenkins) box running on Linux.
Looks like the exclude pattern is applied to the relative path of the files (i.e. relative to your root folder), which explains why it works for folders under your root folder.
Using an excludeSpec (see Gradle Test task DSL) should work fine:
exclude { it.file.canonicalPath.contains('/disabled/')}
Of course, pay attention to / vs \ according to your OS.

Categories