Модульное тестирование создания базы данных SQLite с использованием Spock и Robospock
spock-core:0.7-groovy-2.0
robospock:0.5.0
Android Studio 0.8.2
Fedora release 20 (Heisenbug)
Это полное решение. Теперь он скомпилирует и запускает unit test успешно, а структура каталогов совпадает с редактированием предварительного просмотра. Пожалуйста, не стесняйтесь комментировать все, что не выглядит правильным.
Изменить решение =====
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, без изменений с 5 августа Редактировать
Edit 5 August ================
В основном, я пытаюсь создать JAR файл, который будет использоваться в приложении для Android, который будет иметь функциональные возможности SQLite, поэтому я могу использовать этот JAR файл для многих приложений.
Я начал с нуля и создал небольшое приложение, которое легче исправить. Это структура каталогов, и есть только три файла:
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
}
}
Ошибка, которую я все еще получаю, следующая:
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)
Редактировать 4 августа ===================
Это моя обновленная спецификация теста, которая использует Robolectric для генерации контекста, который может использоваться в конструкторе SQLiteOpenHelper (...)
import org.robolectric.Robolectric
def 'Create an SQLite database for Android'() {
setup:
def androidDB = new SnapzAndroidDB(Robolectric.application)
expect:
androidDB != null
}
Функция, которую я фактически тестирую, представляет собой класс, который расширяет SQLiteOpenHelper
. И мой конструктор SnapzAndroidDB(...)
вызывает конструктор SQLiteOpenHelper()
, так как вы можете видеть, что контекст - это первый параметр, который передается из тестовой спецификации:
public class SnapzAndroidDB extends SQLiteOpenHelper
public SnapzAndroidDB(Context context) {
super(context, SnapzContract.DB_NAME, null, SnapzContract.DB_VERSION);
}
.
.
}
Когда я запускаю свой тест, я получаю эту ошибку:
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 =======================
Изменить ====
Когда я пытаюсь использовать getBaseContext(), я получаю следующую ошибку:
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)
Моя функция spock для этой функции:
def 'Create an SQLite database for Android'() {
setup:
def androidDB = new SnapzAndroidDB(getBaseContext())
expect:
androidDB != null
}
Вот зависимости:
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'
}
====
Я занимаюсь тестированием модулей Spock для своей библиотеки, написанной на Java, которая будет использоваться в моем приложении для Android.
Java JAR файл, который будет развернут в приложении Android для работы с базой данных. Это этот JAR файл, который я тестирую.
Я написал спецификацию Spock для тестирования создания базы данных SQLite.
В моем Java JAR файле у меня есть класс, который создает базу данных SQLite, и я хочу проверить это в моем Spock unit test.
Однако проблема заключается в том, что конструктор SQLiteOpenHelper
должен вызываться с помощью Context, и я пытаюсь высмеять этот контекст, используя import android.text.mock.MockContext
в моем 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);
}
.
.
}
Теперь в моей спецификации тестирования устройства у меня есть это в моем 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
}
Из этого вы можете видеть, что я издеваюсь над контекстом и отправляю его как параметр в конструктор моего класса, который вызовет конструктор SQLiteOpenHelper.
Ошибка, которую я получаю при запуске my unit test, такова:
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.
Будучи новым для Spock Я не уверен, что это возможно или нет, поскольку я просто тестирую свой JAR файл.
Ответы
Ответ 1
Проблема, с которой вы сталкиваетесь, - это правильный контекст для создания БД.
Ваша первая попытка с getBaseContext() не работала, так как не обнаружила такую функцию в SnapClientTest: "Нет сигнатуры метода"
Во второй попытке вы создаете экземпляр MockContext - это незавершенная реализация, которую вы не можете использовать напрямую.
http://developer.android.com/reference/android/test/mock/MockContext.html
"Макет класса" Контекст ". Все методы нефункциональны и выбрасывают UnsupportedOperationException."
Try:
def androidDB = new SnapzAndroidDB(Robolectric.application)
Согласование http://robospock.org/ Robolectric.application должно дать рабочий контекст.
Обновление
Я просто заметил, что вы не распространяете RoboSpecification, но Спецификация:
import pl.polidea.robospock.RoboSpecification
и
class SnapClientTest extends RoboSpecification
Ответ 2
Spock - одна из наиболее широко используемых фреймворков в экосистеме Groovy и Java, которая позволяет создавать тесты BDD в очень интуитивно понятный язык и облегчает некоторые общие задачи, такие как насмешка и расширяемость. Что отличает его от толпы, так это ее прекрасный и очень выразительный язык спецификаций. Благодаря своему игроку JUnit Spock совместим с большинством IDE, инструментами построения и серверами непрерывной интеграции. Чтобы работать со Spock, вам в основном нужно выполнить набор шагов, например следующий рецепт, который позволит вам эффективно реализовать как unit test и веб-интеграции.
Ваше текущее сообщение об ошибке:
Create a sqlite database for Android FAILED
Попробуйте выполнить следующие действия и посмотрите, как это сделать:
Включение в свой код getWritableDatabase и getReadableDatabase должно помочь:
jokesHelper dbHelper = new jokesHelper(getBaseContext());
SQLiteDatabase db = dbHelper.getWritableDatabase();
Таким образом, Android сможет управлять и кэшировать connection.
Тем не менее, если у вас есть сообщение об ошибке из getBaseContext, попробуйте удалить плагин тестирования и заново создать ресурсы STS (.classpath и .project) с помощью метода integrate-with -eclipse, тогда он должен работает.
Если у вас возникли проблемы с getSpecificationContext, это означает, что некоторые детали были опущены, и вам нужно дважды проверить свои спецификации.
Если вы не используете Eclipse, создайте Java Jar с помощью spock, вы можете связать его с Emacs с помощью командной строки Java development как обычный, например Suns JDK или любой другой подход, ожидаемый для Enterprise Development. Чтобы запускать SampleTest, вы должны вызвать тестовую задачу из командной строки с помощью свойства Java system:
gradle -Dtest.single=Sample test
Или, альтернативно,
gradle -Dtest.single=SoapTest clean test
Также проверьте, какие права используются в используемом каталоге. И если вы еще не сделали этого, не забудьте включить зависимости:
dependencies {
classpath 'com.android.tools.build:gradle:0.8.+'
classpath 'org.robospock:robospock-plugin:0.4.0'
}
И сообщите тестовому каталогу, что вы используя, например. srcDirs. И имейте в виду, что важно импортировать правильный ресурс по классу. Как таковой, также include для "build.gradle" в "defaultConfig":
testPackageName "com.yourpackage.test"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
testFunctionalTest true
Spock и Robospock являются инновационными инструментами, которые могут помочь полезным ресурсам для разработки unit test. В качестве альтернативы вы также можете использовать такие инструменты, как TCL Tests. Тесты TCL - это самый старый набор тестов для SQLite и это лучший подход, который вы можете предпринять. Фактически, SQLite начал жизнь как расширение Tcl. Большая часть инструментов тестирования и разработки для SQLite написана в Tcl. В дополнение к собственному API C, расширение Tcl является единственным API, поддерживаемым основной командой SQLite.
Чтобы включить привязки Tcl, загрузите распределение источника SQLite TEA (Tcl Extension Architecture) из сайта SQLite. Эта версия кода - это, по сути, распределение амальгамирования с
Tcl привязывается к концу. Это будет встроено в расширение Tcl, которое затем может быть импортировано в любую среду Tcl.
![enter image description here]()
Необходимо соблюдать конкретные шаги, и важно внимание к каждому detail, так как это может иметь значение для успешного тестирования. запустить или нет.
инструментальная среда является основой структуры тестирования.
Инструментарий контролирует тестируемое приложение и позволяет впрыскивать макетные компоненты, необходимые для запуска приложения. Например, вы можете создавать mock Contexts перед запуском приложения и использовать приложение.
![enter image description here]()
Все взаимодействие приложения с окружающей средой можно контролировать с помощью этого подхода. Вы также можете изолировать свое приложение в ограниченной среде, чтобы иметь возможность прогнозировать результаты, форсировать значения, возвращаемые некоторыми методами, или издеваться над постоянными и неизменными данными для ContentProvider, баз данных или даже содержимого файловой системы. Поэтому также важно указать в своей деятельности информацию, которую вы используете 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>
Если вы запускаете JNI для управления своей базой данных с помощью собственного кода, есть два способа загрузить расширение с помощью SQLite. Один из них - через вызов API C, а один - через функцию SQL, которая ссылается на тот же код, что и функция C API. В обоих случаях вы указываете имя файла и, необязательно, имя функции точки входа:
int sqlite3_load_extension( sqlite3 *db, const char *ext_name,
const char *entry_point, char **error )
Другим способом загрузки загружаемого расширения является встроенная функция SQL:
load_extension( 'ext_name' )
load_extension( 'ext_name', 'entry_point' )
Эта функция аналогична вызову C sqlite3_load_extension() с одним основным ограничением. Поскольку это функция SQL, когда она вызывается, по определению будет выполняться оператор SQL, когда загружается расширение. Это означает, что любое расширение, загруженное с помощью функции load_extension() SQL, полностью не сможет переопределить
или удалить пользовательскую функцию, включая специализированный набор функций like(). Подходы к загрузке данных с помощью подходящего синтаксиса работают аналогично Java, поскольку ожидается.
![enter image description here]()
Директивы отладки используются только для тестирования и разработки
поскольку они добавляют значительные накладные расходы и заставляют все работать заметно медленнее, точно так же, как включение throws Exception. Когда вы выполняете unit test, вам необходимо установить , а также проверить, чтобы ваша база данных не получала corrupted. В принципе, улучшение наилучшей настройки ваших параметров отладки улучшится и поможет вам плавно перейти на наилучшим образом выполнить ваше тестирование. p >
В дополнение ко всем другим директивам сборки SQLite имеет достаточное количество директив SQLite_OMIT_ * для компиляции. Они предназначены для удаления основных функций из сборки, чтобы сделать базовую библиотеку баз данных как можно более компактной и компактной. Чтобы использовать большинство этих директив, вы должны создавать SQLite из источников разработки, найденных в дереве управления версиями. Большинство пропущенных директив не работают
правильно, когда применяется к источнику распространения или к предварительно построенному объединению. Также имейте в виду, что эти директивы времени компиляции официально не поддерживаются в том смысле, что они не являются частью официальной цепочки тестирования. Для любой данной версии SQLite могут возникать проблемы с компиляцией и проблемами времени выполнения, если разрешены произвольные флаги опускания.
![enter image description here]()
Конечно, вам не нужно быть самурай для запуска unit test для SQLite на Android, хотя это может помочь.