将 Google Analytics 与 Robolectric 结合使用时出现 SQLException(或“尝试在 Robolectric 中使用 SQLite3”)
我正在使用 robolectric 来测试利用 Google Analytics 的活动。不幸的是,每当我尝试启动该活动时,我都会收到以下异常。
android.database.SQLException
at com.xtremelabs.robolectric.shadows.ShadowSQLiteDatabase.execSQL(ShadowSQLiteDatabase.java:149)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java)
at com.google.android.apps.analytics.PersistentEventStore$DataBaseHelper.onCreate(Unknown Source)
at com.xtremelabs.robolectric.shadows.ShadowSQLiteOpenHelper.getWritableDatabase(ShadowSQLiteOpenHelper.java:52)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java)
at com.google.android.apps.analytics.PersistentEventStore.<init>(Unknown Source)
at com.google.android.apps.analytics.GoogleAnalyticsTracker.start(Unknown Source)
at com.google.android.apps.analytics.GoogleAnalyticsTracker.start(Unknown Source)
...
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "CREATE TABLE EVENTS ( 'event_id'[*] BIGINT(19) PRIMARY KEY AUTO_INCREMENT NOT NULL, 'user_id' BIGINT(19) NOT NULL, 'account_id' CHAR(256) NOT NULL, 'random_val' BIGINT(19) NOT NULL, 'timestamp_first' BIGINT(19) NOT NULL, 'timestamp_previous' BIGINT(19) NOT NULL, 'timestamp_current' BIGINT(19) NOT NULL, 'visits' BIGINT(19) NOT NULL, 'category' CHAR(256) NOT NULL, 'action' CHAR(256) NOT NULL, 'label' CHAR(256), 'value' BIGINT(19), 'screen_width' BIGINT(19), 'screen_height' BIGINT(19)); "; expected "identifier"; SQL statement:
CREATE TABLE events ( 'event_id' bigint(19) PRIMARY KEY auto_increment NOT NULL, 'user_id' bigint(19) NOT NULL, 'account_id' CHAR(256) NOT NULL, 'random_val' bigint(19) NOT NULL, 'timestamp_first' bigint(19) NOT NULL, 'timestamp_previous' bigint(19) NOT NULL, 'timestamp_current' bigint(19) NOT NULL, 'visits' bigint(19) NOT NULL, 'category' CHAR(256) NOT NULL, 'action' CHAR(256) NOT NULL, 'label' CHAR(256), 'value' bigint(19), 'screen_width' bigint(19), 'screen_height' bigint(19)); [42001-147]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
at org.h2.message.DbException.get(DbException.java:167)
at org.h2.message.DbException.getSyntaxError(DbException.java:192)
at org.h2.command.Parser.readColumnIdentifier(Parser.java:2694)
at org.h2.command.Parser.parseCreateTable(Parser.java:4975)
at org.h2.command.Parser.parseCreate(Parser.java:3705)
at org.h2.command.Parser.parsePrepared(Parser.java:320)
at org.h2.command.Parser.parse(Parser.java:275)
at org.h2.command.Parser.parse(Parser.java:247)
at org.h2.command.Parser.prepare(Parser.java:201)
at org.h2.command.Parser.prepareCommand(Parser.java:214)
at org.h2.engine.Session.prepareLocal(Session.java:425)
at org.h2.engine.Session.prepareCommand(Session.java:374)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1056)
at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:165)
at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:153)
at com.xtremelabs.robolectric.shadows.ShadowSQLiteDatabase.execSQL(ShadowSQLiteDatabase.java:147)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.xtremelabs.robolectric.bytecode.ShadowWrangler.methodInvoked(ShadowWrangler.java:87)
at com.xtremelabs.robolectric.bytecode.RobolectricInternals.methodInvoked(RobolectricInternals.java:110)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java)
at com.google.android.apps.analytics.PersistentEventStore$DataBaseHelper.onCreate(Unknown Source)
at com.xtremelabs.robolectric.shadows.ShadowSQLiteOpenHelper.getWritableDatabase(ShadowSQLiteOpenHelper.java:52)
问题是 Android 使用 SQLite 数据库,但 robolectric 使用 H2,它支持稍微不同的 SQL 风格。
解决这个问题最简单的方法是什么?
I'm using robolectric to test an activity that makes use of Google Analytics. Unfortunately, whenever I try to start up the activity I get the following exception
android.database.SQLException
at com.xtremelabs.robolectric.shadows.ShadowSQLiteDatabase.execSQL(ShadowSQLiteDatabase.java:149)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java)
at com.google.android.apps.analytics.PersistentEventStore$DataBaseHelper.onCreate(Unknown Source)
at com.xtremelabs.robolectric.shadows.ShadowSQLiteOpenHelper.getWritableDatabase(ShadowSQLiteOpenHelper.java:52)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java)
at com.google.android.apps.analytics.PersistentEventStore.<init>(Unknown Source)
at com.google.android.apps.analytics.GoogleAnalyticsTracker.start(Unknown Source)
at com.google.android.apps.analytics.GoogleAnalyticsTracker.start(Unknown Source)
...
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "CREATE TABLE EVENTS ( 'event_id'[*] BIGINT(19) PRIMARY KEY AUTO_INCREMENT NOT NULL, 'user_id' BIGINT(19) NOT NULL, 'account_id' CHAR(256) NOT NULL, 'random_val' BIGINT(19) NOT NULL, 'timestamp_first' BIGINT(19) NOT NULL, 'timestamp_previous' BIGINT(19) NOT NULL, 'timestamp_current' BIGINT(19) NOT NULL, 'visits' BIGINT(19) NOT NULL, 'category' CHAR(256) NOT NULL, 'action' CHAR(256) NOT NULL, 'label' CHAR(256), 'value' BIGINT(19), 'screen_width' BIGINT(19), 'screen_height' BIGINT(19)); "; expected "identifier"; SQL statement:
CREATE TABLE events ( 'event_id' bigint(19) PRIMARY KEY auto_increment NOT NULL, 'user_id' bigint(19) NOT NULL, 'account_id' CHAR(256) NOT NULL, 'random_val' bigint(19) NOT NULL, 'timestamp_first' bigint(19) NOT NULL, 'timestamp_previous' bigint(19) NOT NULL, 'timestamp_current' bigint(19) NOT NULL, 'visits' bigint(19) NOT NULL, 'category' CHAR(256) NOT NULL, 'action' CHAR(256) NOT NULL, 'label' CHAR(256), 'value' bigint(19), 'screen_width' bigint(19), 'screen_height' bigint(19)); [42001-147]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
at org.h2.message.DbException.get(DbException.java:167)
at org.h2.message.DbException.getSyntaxError(DbException.java:192)
at org.h2.command.Parser.readColumnIdentifier(Parser.java:2694)
at org.h2.command.Parser.parseCreateTable(Parser.java:4975)
at org.h2.command.Parser.parseCreate(Parser.java:3705)
at org.h2.command.Parser.parsePrepared(Parser.java:320)
at org.h2.command.Parser.parse(Parser.java:275)
at org.h2.command.Parser.parse(Parser.java:247)
at org.h2.command.Parser.prepare(Parser.java:201)
at org.h2.command.Parser.prepareCommand(Parser.java:214)
at org.h2.engine.Session.prepareLocal(Session.java:425)
at org.h2.engine.Session.prepareCommand(Session.java:374)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1056)
at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:165)
at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:153)
at com.xtremelabs.robolectric.shadows.ShadowSQLiteDatabase.execSQL(ShadowSQLiteDatabase.java:147)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.xtremelabs.robolectric.bytecode.ShadowWrangler.methodInvoked(ShadowWrangler.java:87)
at com.xtremelabs.robolectric.bytecode.RobolectricInternals.methodInvoked(RobolectricInternals.java:110)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java)
at com.google.android.apps.analytics.PersistentEventStore$DataBaseHelper.onCreate(Unknown Source)
at com.xtremelabs.robolectric.shadows.ShadowSQLiteOpenHelper.getWritableDatabase(ShadowSQLiteOpenHelper.java:52)
The problem is that Android uses SQLite databases, but robolectric is using H2 which support a slightly different flavor of SQL.
What's the easiest way to get around this problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
通过为 SQLiteDatabase 实现我自己的 Shadow 类并将其绑定到自定义测试运行器中,我能够完成大部分工作。如果您不使用自定义测试运行程序,则可以将其绑定在测试设置方法中。
您的类路径中需要 com.zentus v056 sqlite-jdbc 驱动程序。
我已经验证这使用 SQLite 而不是 H2,尽管我在使用此解决方案时遇到了新错误:
I was able to get most of the way there by implementing my own Shadow class for the SQLiteDatabase and binding it in a custom test runner. You can probably bind it in your test setup methods instead if you're not using a custom test runner.
You'll need com.zentus v056 sqlite-jdbc driver in your classpath.
I've verified that this uses SQLite instead of H2, although I'm getting a new error with this solution:
Robolectric 现在提供 @UsingDatabaseMap 注释,以便其他数据库可以轻松地与 Roboelectric 一起使用。 (目前这需要 Robolectric 的 SNAPSHOT 版本,Robolectric-1.0-RC5-SNAPSHOT)
如果有人希望将 SQLite 与 Robolectric 一起使用,我建议他们在 github 上查看我的项目,该项目提供了 SQLiteMap 类,以便可以将 SQLite 与 Robolectric 一起使用。
https://github.com/cessationoftime/robolectric-sqlite/wiki
结果是测试注释为使用 SQLite 数据库而不是 H2 的类:
Robolectric now provides the @UsingDatabaseMap annotation so that other databases can easily be used with Roboelectric. (Currently this requires the SNAPSHOT version of Robolectric, Robolectric-1.0-RC5-SNAPSHOT)
If anyone wishes to use SQLite with Robolectric, I recommend they check out my project on github which provides the SQLiteMap class so one can use SQLite with Robolectric.
https://github.com/cessationoftime/robolectric-sqlite/wiki
The result is test classes annotated to use the SQLite database instead of H2: