像Factory Factory这样的框架是否存在?
Factory Girl是一个方便的rails框架,可以轻松创建测试模型实例。
来自Factory Girl主页 :
factory_girl允许您快速定义每个模型的原型,并询问具有对手头测试很重要的属性的实例。
一个例子(也来自主页):
Factory.sequence :email do |n| "somebody#{n}@example.com" end # Let's define a factory for the User model. The class name is guessed from the # factory name. Factory.define :user do |f| # These properties are set statically, and are evaluated when the factory is # defined. f.first_name 'John' f.last_name 'Doe' f.admin false # This property is set "lazily." The block will be called whenever an # instance is generated, and the return value of the block is used as the # value for the attribute. f.email { Factory.next(:email) } end
如果我需要一个用户可以打电话
test_user = Factory(:user, :admin => true)
这将产生具有工厂原型中指定的所有属性的用户, 除了我明确指定的admin属性。 另请注意,电子邮件工厂方法每次调用时都会生成不同的电子邮件。
我认为为Java实现类似的东西应该很容易,但我不想重新发明轮子。
PS:我知道JMock和EasyMoc,但我不是在谈论一个模拟框架。
一个可能的库是Usurper 。
但是,如果要指定要创建的对象的属性,那么Java的静态类型会使框架毫无意义。 您必须将属性名称指定为字符串,以便框架可以使用reflection或Java Bean内省查找属性访问器。 这将使重构变得更加困难。
只是新建对象并调用它们的方法要简单得多。 如果要在测试中避免大量样板代码, Test Data Builder模式可以提供帮助。
我也找了一个类似于Factory Girl的Java,但从来没有找到类似的东西。 相反,我从头开始创建了一个解决方案。 用于在Java中生成模型的工厂: Model Citizen 。
受Factory Girl的启发,它使用字段注释来设置模型的默认值, 这是wiki的一个简单示例 :
@Blueprint(Car.class) public class CarBlueprint { @Default String make = "car make"; @Default String manufacturer = "car manufacturer"; @Default Integer mileage = 100; @Default Map status = new HashMap(); }
这将是汽车模型的蓝图。 这被注册到ModelFactory中,可以创建新实例,如下所示:
ModelFactory modelFactory = new ModelFactory(); modelFactory.registerBlueprint( CarBlueprint.class ); Car car = modelFactory.createModel(Car.class);
您可以通过传入Car实例而不是Class并根据需要设置值来覆盖Car模型的值:
Car car = new Car(); car.setMake( "mustang" ); car = modelFactory.createModel( car );
维基有更复杂的例子( 例如使用@Mapped )和更多细节以及更多的花里胡哨。
- 我知道这不适合所有人,但您可以针对Java代码编写Ruby测试代码。 (JTestR)
- 在Java中执行此操作的首选方法是使用Test Data Builder模式。 我认为这种方法并不能真正保证引入框架或外部依赖的复杂性。 我只是没有看到如何使用框架指定更少的内容并从中获取更多内容…… Builder语法基本上等同于FactoryGirl语法。 (有人可以自由地说服我!)
我知道这不是你想要的……
我过去写过一些使用reflection来填充bean值的代码。 基本思想是找到所有的setter并用虚拟值调用每个setter。 我的版本将所有字符串设置为字段名称setName将使用“name”调用,然后将所有整数设置为1,将布尔值设置为true等。
然后,我将其与类似于Object mother和Test Data Builder的模式结合使用。
它为测试数据提供了良好的开端,任何需要特定值的字段都可以作为测试的一部分明确设置。
希望这可以帮助。
我带着相同的问题来到这里,并且需要用于我的集成测试的数据生成工具。 我决定接受Groovy的挑战,这是我的测试选择语言,因为它的紧凑性和function断言 。
我刚刚写了一个小帮手https://gist.github.com/pgaertig/9502960,名为FactoryGrill;),它允许你编写如下的数据脚本。
insert('MyTable', ID: 1, CREATED_AT: new Date(), NAME: 'Example text')
以上相当于:
INSERT INTO MyTable(ID, CREATED_AT, NAME) VALUES (1, ..current date here.., 'Example text')
您可以使用Groovy做更多事情:
import org.apache.commons.lang3.RandomStringUtils; for ( i in 0..9 ) { insert('USERS', CREATED_AT: new Date(), EMAIL: "test${i}@mydomain.com", SALT: RandomStringUtils.randomAlphanumeric(32)); } load(new File('usersettings.groovy').text) //script nesting etc
它不是真正的工厂,因为Groovy中的工厂使用地图构造函数或expandos非常直接。
FactoryGirl的参考资料和其他资料目前无法提供,因为只有〜30LOC才能实现上述目标。 但是如果我对我的解决方案感兴趣,我会在Github上添加一个专门的项目。
如果您的模型对象很简单,则没有理由使用框架来创建它们,只需使用“new”运算符即可。 如果您有复杂的模型(复杂的关系),那么您可以使用spring将它们绑定在一起(即使在测试场景中,您也可以使用spring)
- 但这仅仅是针对数据对象,如果您正在讨论实例化正在执行某些操作的对象,建议使用模拟/存根外部关系而不是使用实际实例。