【发布时间】:2018-01-12 14:16:56
【问题描述】:
我们已将 Spock + Db unit 框架作为自动化单元测试的一部分。
我们现在有 2000 个测试用例(功能),用于 DbUnit 的 150 个规范。
在这里,我们在数据库中添加所需的条目,然后测试每个方法的行为。
我们观察到执行这些测试用例大约需要 2 小时 30 分钟。
我已为 setup 夹具添加时间戳,并在功能方法中添加了时间戳。以下是我的观察:
allergy.dao.AllergyFormDAOSpec > Get Allergy Form STANDARD_OUT
setup method execution started at : Fri Jan 12 19:00:42 IST 2018
allergy.dao.AllergyFormDAOSpec > API to get Allergy Form STANDARD_OUT
Feature method execution started at : Fri Jan 12 19:00:44 IST 2018
Feature method execution ended at: Fri Jan 12 19:00:45 IST 2018
Total time taken to run the one test case: 242
cleanup method execution started at : Fri Jan 12 19:00:45 IST 2018
Total time taken to run a feature method : 2531
在这里,我观察到在设置后加载功能方法平均需要 2-4 秒。但是,原始测试用例的执行时间不到一秒。
我想知道我是否可以得到关于这里可能延迟的指示?因为,2000 个测试用例的 3 秒意味着 Spock 花费了几乎 1 小时和 30 分钟的时间,而不是真正的功能执行。
总而言之,我们希望减少 Spock 测试用例在日常运行时所花费的总时间。
规格
package allergy.dao
import java.util.Date
import org.dbunit.IDatabaseTester;
import org.dbunit.ext.mssql.InsertIdentityOperation;
import allergy.AllergyForm;
import be.janbols.spock.extension.dbunit.DbUnit;
import spock.lang.Shared
import util.MasterSpec
class AllergyFormDAOSpec extends MasterSpec {
def dao = new AllergyFormDAO();
@Shared Date timeStart1
@Shared Date timeEnd1
@DbUnit(configure={ IDatabaseTester it ->
it.setUpOperation = InsertIdentityOperation.REFRESH
it.tearDownOperation = InsertIdentityOperation.DELETE
})
def content = {
allergy_form(formId:99999,formName:'DummySpockForm',displayIndex:1,deleteFlag:0,is_biological:1)
allergy_form_facilities(id:99999,formId:99999,facilityid:2)
form_concentration(id:99999,formId:99999,name:'1:100',deleteflag:0,displayindex:1)
}
def setup(){
timeStart1 = new Date()
println "setup method execution started at : " + timeStart1
}
def "API to test delete Form facility"(){
def startTime = new Date()
println "Feature method execution started at : " + startTime
given:"form Id is given"
def formId = 99999
when:"delete form facilities"
def result =dao.deleteFormFacilities(null, formId)
then:"validate result"
(result>0)==true
def endTime = new Date()
println "Feature method execution ended at: " + endTime
println 'Total time taken to run the one test case: '+ (endTime.getTime() - startTime.getTime())
}
def cleanup() {
timeEnd1 = new Date()
println "cleanup method execution started at : " + timeEnd1
def difference = timeEnd1.time - timeStart1.time
println "Total time taken to run a fixture method : " + difference
}
}
MasterSpec
package util
import com.ecw.dao.SqlTranslator
import catalog.Root
import spock.lang.Shared
import spock.lang.Specification
import javax.sql.DataSource
/**
*/
class MasterSpec extends Specification {
@Shared
Properties properties = new Properties()
@Shared
public DataSource dataSource
@Shared
protected xmlDataSource = [:]
static int timeCntr = 0;
//setup is to read xml file's content in xmlDataSource Hashmap
def setup(){
//Get Running Class name without its package
def className = this.class.name.substring(this.class.name.lastIndexOf('.') + 1)
def resourceAnno = specificationContext.currentFeature.featureMethod.getAnnotation(FileResource)
if(resourceAnno != null){
def files = resourceAnno.xmlFiles()
def packageName = (this.class.package.name).replaceAll('\\.','/')
for(int i=0;i< files.length;i++){
def f = new File("src/test/resources/"+packageName+"/"+className+"/"+files[i])
def engine = new groovy.text.GStringTemplateEngine()
def template = engine.createTemplate(f).make(null)
def xmlString = template.toString()
//load the hashmap with file name as Key and its content in form of string as Value
xmlDataSource.put(files[i].split("\\.")[0],xmlString)
}
}
}
def setupSpec() {
Date timeStart = new Date()
File propertiesFile = new File('src/test/webapps/myApp/conf/connection.properties').withInputStream {
properties.load it
}
String strDBName = getPropertyValue("myApp.DBName")
if(strDBName.indexOf('?') > -1){
strDBName = strDBName.substring(0, strDBName.indexOf('?'))
}
String strServerName = getPropertyValue("myApp.DBHost");
if(strServerName.indexOf(':') > -1){
strServerName = strServerName.substring(0, strServerName.indexOf(':'))
}
String strUrl = getPropertyValue("myApp.DBUrl")
String strPort = strUrl.substring(strUrl.lastIndexOf(':') + 1)
//FOR MSSQL
System.setProperty("myApp.SkipJndi", "yes")
//dataSource = new JtdsDataSource()
Object newObject = null;
if(SqlTranslator.isDbSqlServer()){
newObject = Class.forName("net.sourceforge.jtds.jdbcx.JtdsDataSource").newInstance()
} else if(SqlTranslator.isDbMySql()){
newObject = Class.forName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource").newInstance()
}
dataSource = (DataSource)newObject
dataSource.setDatabaseName(strDBName)
dataSource.setUser(getPropertyValue("myApp.DBUser"))
dataSource.setPassword(getPropertyValue("myApp.DBPassword"))
dataSource.setServerName(strServerName)
dataSource.setPortNumber(Integer.parseInt(strPort))
}
}
【问题讨论】:
-
没有任何代码我们只能胡乱猜测。
-
一位经验丰富且信誉评分高的会员提出的如此模糊的问题令人难以置信。我认为您应该知道如何就 SO 提出问题。
-
@kriegaex:我可以发布代码。但是,我试图了解 Spock 的生命周期,或者是否有人经历过这样的经历。让我放下整个规范..
标签: unit-testing spock dbunit