28

Factory Girl 是 Rails 中一个方便的框架,用于轻松创建模型实例以进行测试。

来自工厂女孩主页

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)

这将产生一个具有工厂原型中指定的所有属性的用户,除了我明确指定的管理属性。另请注意,电子邮件工厂方法每次调用都会产生不同的电子邮件。

我认为为 Java 实现类似的东西应该很容易,但我不想重新发明轮子。

PS:我知道 JMock 和 EasyMoc,但是我不是在这里谈论一个模拟框架。

4

6 回答 6

22

我还寻找了与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();
}

这将是 Car 模型的蓝图。这已注册到 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 );

wiki有更复杂的示例(例如使用 @Mapped)和更多花里胡哨的细节。

于 2012-09-04T06:38:08.540 回答
8

一个可能的库是Usurper

但是,如果您想指定正在创建的对象的属性,那么 Java 的静态类型会使框架变得毫无意义。您必须将属性名称指定为字符串,以便框架可以使用反射或 Java Bean 自省查找属性访问器。这将使重构变得更加困难。

只新建对象并调用它们的方法要简单得多。如果您想避免在测试中使用大量样板代码,Test Data Builder模式可以提供帮助。

于 2009-06-14T18:52:34.800 回答
2
  1. 我知道这并不适合所有人,但您可以针对您的 Java 代码编写 Ruby 测试代码。(JTestR)
  2. 在 Java 中执行此操作的首选方法是使用Test Data Builder模式。我认为这种方法并不真正保证引入框架或外部依赖的复杂性。我只是不明白您如何可以使用框架来指定更少的内容并从中获得更多东西...... Builder 语法本质上等同于您的 FactoryGirl 语法。(有人可以随意说服我!)
于 2009-06-13T18:18:55.530 回答
1

我知道这不是你要找的……

我过去写了一些代码,使用反射来填充 bean 值。基本思想是找到所有的设置器并用一个虚拟值调用每个设置器。我的版本将所有字符串设置为字段的名称 setName 将使用“名称”调用,然后将所有整数设置为 1,将布尔值设置为 true 等。

然后我将它与类似于 Object Mother 和 Test Data Builder 的模式结合使用。

它为测试数据提供了一个良好的开端,任何需要特定值的字段都可以明确设置为测试的一部分。

希望这可以帮助。

于 2009-06-14T17:08:02.213 回答
1

我带着同样的问题来到这里,我的集成测试需要数据生成工具。我决定接受 Groovy 的挑战,这是我选择的测试语言,因为它的紧凑性和强大的 assert

我刚刚编写了一个名为 FactoryGrill 的小助手https://gist.github.com/pgaertig/9502960 ;) 它允许您编写如下所示的数据脚本。

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 中使用map 构造函数expandos非常简单。

FactoryGirl 的参考资料和其他内容目前不可用,因为上述内容仅通过 ~30LOC 实现。但是,如果对我的解决方案感兴趣,我将在 Github 上添加一个专门的项目。

于 2014-03-12T08:50:39.403 回答
-3

如果您的模型对象很简单,则没有理由使用框架来创建它们,只需使用“new”运算符即可。如果您有复杂的模型(复杂的关系),那么您可以使用 spring 将它们绑定在一起(即使在测试场景中您也可以使用 spring)

  • 但这只是针对数据对象,如果您正在谈论实例化正在做某事的对象,建议模拟/存根外部关系而不是使用真实实例。
于 2009-06-12T13:09:06.033 回答