基于JFactory的测试工具库,为验收测试提供相对标准的数据准备和断言支持。
测试代码可以通过注入JData后直接调用接口方法的方式准备测试数据,也可以通过内置的预定义Cucumber Step用数据表格来准备数据。
无论以哪种形式准备数据,JData都会通过一些字符串形式的表达式表明某些特定的语意,假如如下的JFactory Spec已经注册:
public class Products {
public static class 商品 extends Spec<Product> {
@Override
public void main() {
property("stocks").reverseAssociation("product");
}
@Trait
public 商品 红色的() {
property("color").value("red");
return this;
}
}
}
通常会用到如下的几个表达式参数:
- traitsSpec 要准备数据的Trait和Spec,比如可以用如下代码构造一个商品集合
jData.prepare("红色的 商品",new HashMap<String, String>(){{
put("name","book");
}});
- queryExpression 对象检索表达式,基本形式为"Spec.property-chain[value]",表示对应Spec所指类型的所有对象中,返回属性为value的那些对象, 如下的表达式可以解释为检索出name为book的"商品"。
List<Product> products=jData.queryAll("商品.name[book]");
Product product=jData.query("商品.name[book]");
- beanProperty 对象属性标识,该标识由两部分组成,其形式可以理解为:queryExpression.property,前半部分为对象检索表达式,表示要针对哪个对象, property为属性名。该标识主要用于为已存在的对象关联子对象。
- 给定部分属性值,准备对象
<T> List<T> prepare(String traitsSpec,Table table)
<T> List<T> prepare(String traitsSpec,Map<String, ?>...data)
<T> List<T> prepare(String traitsSpec,List<Map<String, ?>>data)
- 以默认属性值,准备一定数量的对象
<T> List<T> prepare(int count,String traitsSpec)
- 查询某些符合条件的数据
<T> T query(String queryExpression)
<T> Collection<T> queryAll(String queryExpression)
- 为已存在的对象准备子对象数据
<T> List<T> prepareAttachments(String beanProperty,String traitsSpec,List<Map<String, ?>>data)
- 为已存在的对象准备默认子对象数据
<T> List<T> prepareAttachments(String beanProperty,int count,String traitsSpec)
- 为已存在的对象通过反向关联准备子对象数据
<T> List<T> prepareAttachments(String traitsSpec,String reverseAssociationProperty,String queryExpression,
List<Map<String, ?>>data)
- 为已存在的对象通过反向关联准备默认子对象数据
<T> List<T> prepareAttachments(int count,String traitsSpec,String reverseAssociationProperty,String queryExpression)
以上的API除检索数据接口外,都可以通过Cucumber Step的方式直接调用,假如有如下对象关系:
//Entity
public class Cart {
public String customer;
public List<Product> products = new ArrayList<>();
}
public class Product {
public String name;
public String color;
public List<ProductStock> stocks = new ArrayList<>();
}
public class ProductStock {
public Product product;
public String size;
public int count;
}
public class Order {
public String customer;
public Product product;
}
//Spec
public static class 购物车 extends Spec<Cart> {
}
public static class 订单 extends Spec<Order> {
}
public static class 商品 extends Spec<Product> {
@Override
public void main() {
property("stocks").reverseAssociation("product");
}
@Trait
public 商品 红色的() {
property("color").value("red");
return this;
}
}
public static class 库存 extends Spec<ProductStock> {
}
那么可以通过内建Step完成如下数据准备:
- 给定部分属性值,准备对象
假如存在"商品":
| name |
| book |
- 以默认属性值,准备一定数量的对象
假如存在1个"红色的 商品"
- 为已存在的对象准备子对象数据
# 购物车 has many 商品 through Cart::products
假如存在"购物车":
| customer | products[0](商品).name |
| Tom | book |
并且存在"购物车.customer[Tom].products"的"商品":
| name |
| bicycle |
# 订单 has one 商品 through Order::product
假如存在"订单":
| customer |
| Tom |
并且存在"订单.customer[Tom].product"的"商品":
| name |
| bicycle |
- 为已存在的对象准备默认子对象数据
假如存在"购物车":
| customer |
| Tom |
并且存在"购物车.customer[Tom].products"的1个"商品"
- 为已存在的对象通过反向关联准备子对象数据
# 库存 belongs to 商品 through ProductStock::product
假如存在"商品":
| name |
| book |
并且存在如下"库存",并且其"product"为"商品.name[book]":
| size | count |
| A3 | 10 |
- 为已存在的对象通过反向关联准备默认子对象数据
假如存在"商品":
| name |
| book |
并且存在1个"库存",并且其"product"为"商品.name[book]"
注意目前只支持中文环境
一个多层对象尤其是Map或者JSON,用Java语言对其子属性进行测试断言是比较麻烦的。因此这里引入了一个专门断言对象数据的工具语言。 这个语言在解析执行时总是针对一个被断言对象,然后用"."运算符访问其子属性。用"[]" 运算符访问集合元素。并且数据是没有类型的。
比如判断一个被测对象的name属性是"Tom",age属性是19,可以如下表达:
.name='Tom' and .age=19
- 检索一个对象并断言
void should(String queryExpression,String dalExpression)
- 检索对象集合并断言
void allShould(String queryExpression,String dalExpression)
- 检索一个对象并断言
那么"商品.name[book]"应为:
"""
.name='book'
"""
- 检索对象集合并断言
那么所有"商品"应为:
"""
.size=1
and [0].name='book'
"""
一个完整的创建数据断言数据的例子(这不是一个有意义的测试,只是说明测试数据准备和断言)
场景: 创建并检查数据
假如存在"商品":
"""
name: book
"""
那么所有"商品"应为:
"""
.size=1
and [0].name='book'
"""
那么"商品.name[book]"应为:
"""
.name='book'
"""
更多文档请看下面