像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 )和更多细节以及更多的花里胡哨。

  1. 我知道这不适合所有人,但您可以针对Java代码编写Ruby测试代码。 (JTestR)
  2. 在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)

  • 但这仅仅是针对数据对象,如果您正在讨论实例化正在执行某些操作的对象,建议使用模拟/存根外部关系而不是使用实际实例。
Interesting Posts