我有以下Grails 2.4.3 Domain类
package invoicer
class Product {
Float price
Float taxRate
Float tax
static mapping = {
tax formula: 'PRICE * TAX_RATE'
}
}
我已创建此集成测试以验证公式是否正确计算
package invoicer;
import spock.lang.Specification
class ProductIntegrationSpec extends Specification {
def "Test tax calculation"() {
when:
def p = new Product(price: 5.00, taxRate: 0.25)
p.save(failOnError:true, flush: true)
then:
def newProduct = Product.get(1)
newProduct.tax == (5.00 * 0.25)
}
}
此测试总是失败
grails> test-app -integration ProductIntegrationSpec
2014-10-16 11:29:15,225 [main] DEBUG hibernate.SQL -
drop table product if exists
2014-10-16 11:29:15,230 [main] DEBUG hibernate.SQL -
create table product (
id bigint generated by default as identity,
version bigint not null,
price float not null,
tax_rate float not null,
primary key (id)
)
======================================================================
Application: Invoicer 0.1
-------------------------
Environment: TEST
Database configuration:
Hibernate DDL mode: create
URL: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
Driver: org.h2.Driver
User: sa
======================================================================
| Running 1 integration test... 1 of 1
2014-10-16 11:29:17,797 [main] DEBUG hibernate.SQL -
/* insert invoicer.Product
*/ insert
into
product
(id, version, price, tax_rate)
values
(null, ?, ?, ?)
2014-10-16 11:29:17,798 [main] TRACE sql.BasicBinder - binding parameter [1] as [BIGINT] - [0]
2014-10-16 11:29:17,798 [main] TRACE sql.BasicBinder - binding parameter [2] as [FLOAT] - [5.0]
2014-10-16 11:29:17,798 [main] TRACE sql.BasicBinder - binding parameter [3] as [FLOAT] - [0.25]
| Failure: Test tax calculation(invoicer.ProductIntegrationSpec)
| Condition not satisfied:
newProduct.tax == (5.00 * 0.25)
| | | |
| | false 1.2500
| null
invoicer.Product : 1
at invoicer.ProductIntegrationSpec.Test tax calculation(ProductIntegrationSpec.groovy:14)
| Completed 1 integration test, 1 failed in 0m 0s
| Tests FAILED - view reports in /Users/XXX/git/invoicer/target/test-reports
我不明白为什么会失败,所以我在Grails控制台中尝试了这段代码
import invoicer.*
def p = new Product(price: 5.00, taxRate: 0.25)
p.save(failOnError: true, flush: true)
def newProduct = Product.get(1)
assert newProduct.tax == (5.00 * 0.25)
它以第一次在控制台中运行
的方式失败groovy> import invoicer.*
groovy>
groovy> def p = new Product(price: 5.00, taxRate: 0.25)
groovy> p.save(failOnError: true, flush: true)
groovy>
groovy> def newProduct = Product.get(1)
groovy> assert newProduct.tax == (5.00 * 0.25)
2014-10-16 11:34:31,140 [Thread-12] DEBUG hibernate.SQL -
/* insert invoicer.Product
*/ insert
into
product
(id, version, price, tax_rate)
values
(null, ?, ?, ?)
2014-10-16 11:34:31,162 [Thread-12] TRACE sql.BasicBinder - binding parameter [1] as [BIGINT] - [0]
2014-10-16 11:34:31,163 [Thread-12] TRACE sql.BasicBinder - binding parameter [2] as [FLOAT] - [5.0]
2014-10-16 11:34:31,164 [Thread-12] TRACE sql.BasicBinder - binding parameter [3] as [FLOAT] - [0.25]
Exception thrown
Assertion failed:
assert newProduct.tax == (5.00 * 0.25)
| | | |
| | false 1.2500
| null
invoicer.Product : 1
at ConsoleScript0.run(ConsoleScript0:7)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1270)
虽然在同一个控制台会话中再次运行,但它的工作正常!
groovy> import invoicer.*
groovy>
groovy> def p = new Product(price: 5.00, taxRate: 0.25)
groovy> p.save(failOnError: true, flush: true)
groovy>
groovy> def newProduct = Product.get(1)
groovy> assert newProduct.tax == (5.00 * 0.25)
2014-10-16 11:36:20,612 [Thread-13] DEBUG hibernate.SQL -
/* insert invoicer.Product
*/ insert
into
product
(id, version, price, tax_rate)
values
(null, ?, ?, ?)
2014-10-16 11:36:20,613 [Thread-13] TRACE sql.BasicBinder - binding parameter [1] as [BIGINT] - [0]
2014-10-16 11:36:20,613 [Thread-13] TRACE sql.BasicBinder - binding parameter [2] as [FLOAT] - [5.0]
2014-10-16 11:36:20,614 [Thread-13] TRACE sql.BasicBinder - binding parameter [3] as [FLOAT] - [0.25]
2014-10-16 11:36:20,620 [Thread-13] DEBUG hibernate.SQL -
select
product0_.id as id1_7_0_,
product0_.version as version2_7_0_,
product0_.price as price3_7_0_,
product0_.tax_rate as tax_rate4_7_0_,
product0_.PRICE * product0_.TAX_RATE as formula0_0_
from
product product0_
where
product0_.id=?
2014-10-16 11:36:20,621 [Thread-13] TRACE sql.BasicBinder - binding parameter [1] as [BIGINT] - [1]
请注意,第二次运行会记录一个select语句,其中计算税额,但第一次运行时没有;我很难说第一次控制台行为失败的原因以及它第二次正常运行的原因。我想这个问题的答案可以解释为什么集成测试总是失败。谢谢你的想法!
答案 0 :(得分:3)
我终于明白了。致电
save(flush: true)
还不够。关键是重新查询数据库,因为这是where子句生成公式的时候。保存域对象后,必须调用
refresh()
就可以了。重新查询数据库并填充基于公式的字段。