假设我有一个interface Joiner {
String join(List<String> l);
}
界面:
class Java8Joiner implements Joiner {
@Override String join(List<String> l) { String.join("", l); }
}
class GroovyJoiner implements Joiner {
@Override String join(List<String> l) { l.join('') }
}
它的两个实现:
class JoinerSpecification extends Specification {
@Subject
final def joiner = // Joiner instance here
def "Joining #list -> #expectedString"(List<String> list, String expectedString) {
expect:
joiner.join(list) == expectedString
where:
list | expectedString
[] | ''
['a'] | 'a'
['a', 'b'] | 'ab'
}
}
检查这两个或多个实现通过相同测试的最佳方法是什么?
基本上,我想运行JoinerSpecification定义的所有测试,使用Java8Joiner,然后运行GroovyJoiner,依此类推......
<?php
session_start();
if (!isset($_SESSION["manager"])){
header("location: admin_login.php");
exit();
}
$managerID = preg_replace('#[^0-9]#i', '', $_SESSION["id"]);
$manager = preg_replace('#[^A-Za-z0-9]#i', '', $_SESSION["manager"]);
$password = preg_replace('#[^A-Za-z0-9]#i', '', $_SESSION["password"]);
include "scripts/connect.php";
$sql = mysql_query("SELECT * FROM users WHERE id='$managerID' AND username='$manager' AND password='$password' LIMIT 1");
$existCount = mysql_num_rows($sql);
if ($existCount == 0){
echo "The login info you entered does not exist in the database.";
exit();
}
$header ="";
while ($row = mysql_fetch_array($sql)){
$name = $row["name"];
$accounttype = $row["accounttype"];
if($accounttype == "a"){
include_once "menu_a.php";
}else{
include_once "menu_b.php";
}
}
?>
如果需要,重构JoinerSpecification是完全没问题的。
我的主要目标是:
编辑1(2015年6月15日)
重新提出我的问题&amp;添加了一些细节以使其更清晰。
答案 0 :(得分:2)
Opal的建议很有意思,但不切实际。无法使用then blocks是一个显而易见的事。
让我们尝试使用其他方法进行自我回答。由于目标是在同一接口的多个实现上执行相同的规范,为什么不尝试使用良好的旧继承呢?
abstract class AbstractJoinerSpec extends Specification {
abstract Joiner getSubject()
@Unroll
def "Joining #list -> #expectedString"(List<String> list, String expectedString) {
given:
def joiner = getSubject()
expect:
joiner.join(list) == expectedString
where:
list | expectedString
[] | ''
['a'] | 'a'
['a', 'b'] | 'ab'
}
}
class Java8JoinerSpec extends AbstractJoinerSpec {
@Override
Joiner getSubject() { new Java8Joiner() }
}
class GroovyJoinerSpec extends AbstractJoinerSpec {
@Override
Joiner getSubject() { new Java8Joiner() }
}
基本上,唯一的抽象方法是getSubject
,所有继承的测试用例都是由Spock执行的(我在文档中找不到这个功能,但确实有效)。
优点
<强>缺点强>
getSubject
方法。 我认为可以接受这种权衡,因为你不经常手动运行/调试实现。保持代码清洁,并有有意义的报告值得这样的不便。
答案 1 :(得分:1)
这里最有用的是比较链,但据我所知,它没有在groovy中实现,请参阅here。由于根据docs的Subject
目的是纯粹的信息,我提出了以下想法:
@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
@Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class Test extends Specification {
def 'attempt 1'() {
given:
def joiners = [new GroovyJoiner(), new Java8Joiner()]
expect:
joiners.every { it.join(list) == expectedString }
where:
list | expectedString
[] | ''
['a'] | 'a'
['a', 'b'] | 'ab'
}
def 'attempt 2'() {
given:
def gJoiner = new GroovyJoiner()
def jJoiner = new Java8Joiner()
expect:
[gJoiner.join(list), jJoiner.join(list), expectedString].toSet().size() == 1
where:
list | expectedString
[] | ''
['a'] | 'a'
['a', 'b'] | 'ab'
}
}
interface Joiner {
String join(List<String> l);
}
class Java8Joiner implements Joiner {
@Override String join(List<String> l) { String.join("", l); }
}
class GroovyJoiner implements Joiner {
@Override String join(List<String> l) { l.join('') }
}
在尝试1 中,我只是检查列表中的每个元素是否等于expectedString
。它看起来不错但是在错误上它并不够冗长。任何元素都可能失败,并且没有跟踪哪一个。
尝试2 方法使用Set
。由于所有结果应该相等,因此只有一个元素留在集合中。在打印测试失败的详细信息。
我的头脑中还有番石榴的ComparisonChain
,但不知道它是否有用以及它的另一个项目依赖。
答案 2 :(得分:0)
不幸的是,没有办法在Spock中以声明方式创建两个列表的笛卡尔积。您必须定义自己的Iterable,它将为您的变量提供值。
如果您愿意为了可读性而牺牲简洁性,那么有一种更具可读性(使用Spock表格数据定义)的方式来定义数据。如果您感兴趣,请告诉我。否则,这里有一个解决方案,允许您以声明方式定义所有内容,而不会重复,但是您丢失了Spock的精确表格定义。
如果你的实现是无状态的,即它没有保持状态,你就可以使用Joiner的@Shared实例:
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
interface Joiner {
String join(List<String> l);
}
class Java8Joiner implements Joiner {
@Override
String join(List<String> l) { String.join("", l); }
}
class GroovyJoiner implements Joiner {
@Override
String join(List<String> l) { l.join('') }
}
class S1Spec extends Specification {
@Shared
Joiner java8Joiner = new Java8Joiner()
@Shared
Joiner groovyJoiner = new GroovyJoiner()
List<Map> transpose(Map<List> mapOfLists) {
def listOfMaps = [].withDefault { [:] }
mapOfLists.each { k, values ->
[values].flatten().eachWithIndex { value, index ->
listOfMaps[index][k] = value
}
}
listOfMaps
}
Iterable distribute(List<Joiner> joiners, Map<String, List> data) {
def varsForEachIteration = transpose(data)
new Iterable() {
@Override
Iterator iterator() {
[joiners, varsForEachIteration].combinations().iterator()
}
}
}
@Unroll
def "Joining with #joiner #list -> #expectedString"() {
expect:
joiner.join(list) == expectedString
where:
[joiner, data] << distribute([java8Joiner, groovyJoiner], [
list : [[], ['a'], ['a', 'b']],
expectedString: ['', 'a', 'ab']
])
and:
list = data.list
expectedString = data.expectedString
}
}