java android sqlite unit-testing robospock

java - Pruebas unitarias creando una base de datos SQLite usando Spock y Robospock



android unit-testing (2)

spock-core:0.7-groovy-2.0 robospock:0.5.0 Android Studio 0.8.2 Fedora release 20 (Heisenbug)

Esta es la solución completa. Ahora compila y ejecuta la prueba de la unidad con éxito, y la estructura del directorio es la misma que la edición de vista previa. Por favor, siéntase libre de comentar cualquier cosa que no se vea bien.

Editar solución =====

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, sin cambios desde la edición del 5 de agosto

Edit 5 August ================

Básicamente, estoy tratando de crear un archivo JAR que se utilizará en una aplicación de Android que tendrá la funcionalidad de SQLite , por lo que puedo usar este archivo JAR para muchas aplicaciones.

Comencé desde cero y creé una aplicación más pequeña que es más fácil de corregir errores. Esta es la estructura del directorio, y solo hay tres archivos:

testSQLite/build.gradle testSQLite/src/main/java/com/example/sqltest/SnapzAndroidDB.java testSQLite/src/test/groovy/SnapzClientTest.groovy

construir.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 } }

El error que todavía estoy recibiendo es el siguiente:

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)

Editar el 4 de agosto ===================

Esta es mi especificación de prueba actualizada que usa Robolectric para generar un contexto que se puede usar en el constructor de SQLiteOpenHelper (...)

import org.robolectric.Robolectric def ''Create an SQLite database for Android''() { setup: def androidDB = new SnapzAndroidDB(Robolectric.application) expect: androidDB != null }

La función que estoy probando en realidad es una clase que extiende SQLiteOpenHelper . Y mi constructor SnapzAndroidDB(...) llama SQLiteOpenHelper() constructor SQLiteOpenHelper() , como puede ver, el contexto es el primer parámetro que se pasa desde la especificación de prueba:

public class SnapzAndroidDB extends SQLiteOpenHelper public SnapzAndroidDB(Context context) { super(context, SnapzContract.DB_NAME, null, SnapzContract.DB_VERSION); } . . }

Cuando ejecuto mi prueba me sale este 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)

EDICIÓN FINAL =======================

Editar ====

Cuando trato de usar getBaseContext (), aparece el siguiente 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)

Mi función spock especificación es esta:

def ''Create an SQLite database for Android''() { setup: def androidDB = new SnapzAndroidDB(getBaseContext()) expect: androidDB != null }

Aquí están las dependencias:

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'' }

====

Estoy haciendo la prueba de la unidad de Spock para mi biblioteca escrita en Java que se utilizará en mi aplicación de Android.

El archivo JAR de Java que se implementará en una aplicación de Android para realizar tareas de base de datos. Es este archivo JAR que estoy probando.

He escrito una especificación de Spock para probar la creación de una base de datos SQLite.

En mi archivo JAR de Java, tengo una clase que crea la base de datos SQLite y quiero probar eso en mi prueba de unidad de Spock.

Sin embargo, el problema es que el constructor SQLiteOpenHelper debe llamarse con un Contexto, y estoy tratando de burlar ese contexto usando import android.text.mock.MockContext en mi prueba de unidad de Spock.

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); } . . }

Ahora en mi unidad de prueba de especificaciones tengo esto en mi 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 }

De esto se puede ver que estoy burlándome del contexto y enviándolo como un parámetro al constructor de mi clase que llamará al constructor SQLiteOpenHelper.

El error que recibo cuando ejecuto mi prueba de unidad es este:

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.

Como soy nuevo en Spock, no estoy seguro de si esto es posible o no, ya que solo estoy probando mi archivo JAR.


El problema al que te enfrentas es obtener un contexto correcto para crear la base de datos.

Su primer intento con getBaseContext () no funcionó ya que no encontró una función como esa en SnapClientTest: "Sin firma del método"

En su segundo intento, está creando una instancia de MockContext: esta es una implementación de código auxiliar que no puede usar directamente.

http://developer.android.com/reference/android/test/mock/MockContext.html "Una clase de Contexto simulado. Todos los métodos no son funcionales y lanzan la excepción UnsupportedOperationException".

Tratar:

def androidDB = new SnapzAndroidDB(Robolectric.application)

Accoding to http://robospock.org/ Robolectric.application debería proporcionar un contexto de trabajo.

Actualización Me acabo de dar cuenta de que no está extendiendo RoboSpecification pero Especificación:

import pl.polidea.robospock.RoboSpecification

y

class SnapClientTest extends RoboSpecification


Spock es uno de los marcos más utilizados en el ecosistema de Groovy y Java que permite la creación de pruebas BDD en un lenguaje muy intuitivo y facilita algunas tareas comunes como la burla y la extensibilidad. Lo que lo hace destacar entre la multitud es su hermoso y expresivo lenguaje de especificación. Gracias a su corredor JUnit, Spock es compatible con la mayoría de los IDE, herramientas de compilación y servidores de integración continua. Para trabajar con Spock, básicamente necesita realizar una serie de pasos, como seguir una recipe , que le permitirán implementar eficazmente una prueba unitaria y una integración web.

Su mensaje de error actual lee:

Create a sqlite database for Android FAILED

Prueba estos pasos y mira cómo va:

Incluir a su código getWritableDatabase y getReadableDatabase debería ayudar:

jokesHelper dbHelper = new jokesHelper(getBaseContext()); SQLiteDatabase db = dbHelper.getWritableDatabase();

Al hacerlo, Android podrá administrar y almacenar en caché la connection .

Sin embargo, si recibió algún mensaje de error de getBaseContext , intente desinstalar el complemento de prueba y vuelva a crear los recursos STS (.classpath & .project) utilizando integre con --eclipse, entonces debería work .

Si tiene algún problema con getSpecificationContext , significa que se omitieron algunos detalles y debe revisar sus specifications .

En caso de que no esté utilizando Eclipse , para crear su archivo Java Jar con spock, puede interactuar con Emacs a través de las herramientas de desarrollo Java de línea de comandos como de usual , por ejemplo, el JDK de Sun o cualquier otro enfoque esperado para el Desarrollo Empresarial . Para ejecutar solo un SampleTest, debe invocar la tarea de prueba desde la línea de comandos con la propiedad del sistema Java :

gradle -Dtest.single=Sample test

O alternativamente

gradle -Dtest.single=SoapTest clean test

También verifique cuáles son los permissions en el directorio en uso. Y en caso de que aún no lo hayas hecho, recuerda incluir las http://robospock.org/ :

dependencies { classpath ''com.android.tools.build:gradle:0.8.+'' classpath ''org.robospock:robospock-plugin:0.4.0'' }

E informe al directorio de prueba que está using , por ejemplo, srcDirs. Y tenga en cuenta que ( "Es ist wichtig das man hier die richtige Resources-Klasse importiert" ) es importante importar el recurso correcto requerido por la clase. Como tal, también include a "build.gradle" en el "defaultConfig":

testPackageName "com.yourpackage.test" testInstrumentationRunner "android.test.InstrumentationTestRunner" testFunctionalTest true

Spock y Robospock son herramientas innovadoras que pueden ayudar a recursos útiles para el desarrollo de la prueba unitaria . Alternativamente, también puede utilizar herramientas tales como Pruebas TCL. Las pruebas TCL son el conjunto de pruebas más antiguo para SQLite y es el mejor enfoque que puede tomar. De hecho, SQLite comenzó su vida como una extensión Tcl. Gran parte de las herramientas de prueba y desarrollo para SQLite están escritas en Tcl. Además de la API C nativa, la extensión Tcl es la única API admitida por el equipo central de SQLite.

Para habilitar los enlaces Tcl, descargue la distribución TEA (Tcl Extension Architecture) de la fuente SQLite del sitio web SQLite . Esta versión del código es esencialmente la distribución de la amalgama con los enlaces Tcl anexados al final. Esto se construirá en una extensión Tcl que luego se puede importar a cualquier entorno Tcl.

Deben seguirse pasos muy específicos y la atención a cada detail es esencial, ya que puede marcar la diferencia para permitir que sus pruebas se ejecuten con éxito o no.

El marco de instrumentación es la base del marco de pruebas. La instrumentación controla la aplicación bajo prueba y permite la inyección de componentes simulados requeridos por la aplicación para ejecutarse. Por ejemplo, puede crear Contextos simulados antes de que se inicie la aplicación y dejar que la aplicación los use.

Todas las interacciones de la aplicación con el entorno circundante pueden controlarse utilizando este enfoque. También puede aislar su aplicación en un entorno restringido para poder predecir los resultados, forzando los valores devueltos por algunos métodos o burlándose de datos persistentes e invariables para ContentProvider, bases de datos o incluso el contenido del sistema de archivos. Por lo tanto, también es importante especificar en su actividad la información que está ejecutando una 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>

En caso de que ejecute JNI para manipular su base de datos con código nativo, hay dos formas de cargar una extensión con SQLite. Una es a través de una llamada a la API de C, y la otra a través de una función SQL que llama al mismo código que la función de la API de C. En ambos casos, proporciona un nombre de archivo y, opcionalmente, el nombre de la función de punto de entrada:

int sqlite3_load_extension( sqlite3 *db, const char *ext_name, const char *entry_point, char **error )

La otra forma de cargar una extensión cargable es con la función SQL incorporada :

load_extension( ''ext_name'' ) load_extension( ''ext_name'', ''entry_point'' )

Esta función es similar a la llamada C sqlite3_load_extension (), con una limitación importante. Debido a que esta es una función SQL, cuando se llama habrá, por definición, una instrucción SQL que se ejecutará cuando se cargue la extensión. Eso significa que cualquier extensión cargada con la función de carga load_extension () será completamente incapaz de redefinir o eliminar una función personalizada, incluido el conjunto especializado de funciones like (). Los enfoques para cargar los datos con la sintaxis adecuada funcionan de manera similar con Java , como se expected .

Las directivas de depuración solo se usan para fines de prueba y desarrollo, ya que agregan una sobrecarga significativa y hacen que todo se ejecute notablemente más lento, de manera similar a la inclusión de Excepciones . Como está ejecutando la prueba unitaria, debe configurarlos en accordingly y también verificar que la base de datos no se corrupted . Básicamente, lograr la mejor melodía para tus configuraciones de depuración mejorará y te ayudará a que tu prueba funcione de la mejor manera.

Además de todas las otras directivas de compilación, SQLite tiene un buen número de directivas de tiempo de compilación SQLITE_OMIT_ *. Estos están diseñados para eliminar las características principales de la compilación en un esfuerzo por hacer que la biblioteca de base de datos principal sea lo más pequeña y compacta posible. Para utilizar la mayoría de estas directivas de omisión, debe crear SQLite a partir de las fuentes de desarrollo que se encuentran en el árbol de control de origen. La mayoría de las directivas de omitir no funcionarán correctamente cuando se apliquen a una distribución de origen o a la amalgama precompilada. También tenga en cuenta que estas directivas de tiempo de compilación no son compatibles oficialmente, en el sentido de que no forman parte de la cadena oficial de pruebas. Para cualquier versión dada de SQLite, puede haber problemas de compilación y problemas de tiempo de ejecución si se habilitan conjuntos arbitrarios de indicadores de omisión.

Por supuesto, no es necesario ser un samurai para ejecutar la prueba unitaria para SQLite en Android, aunque podría ayudar.