6

When I am writing unit tests in dynamically-typed Ruby or Python, I use the libraries factory_girl and factory_boy, respectively, in order to conveniently generate objects under test. They provide convenient features over direct object instantiation, for example:

  • factory inheritance and overrides
  • field defaults and overrides
  • lazily-computed dependent/derived fields
  • construction of dependent/related other objects
  • implicit lazy field dependency resolution

What are some libraries/frameworks I could use while writing unit tests in statically-typed Java or Scala to achieve similar effects with similar benefits?

Thanks in advance!

I found a similar StackOverflow question from the past here, but unfortunately, the top answer is (paraphrased), "there is no direct equivalent because that would be pointless".

Community
  • 1
  • 1
Ming
  • 1,613
  • 12
  • 27
  • I am not familiar with factory-boy or factory-girl. But it seems that you want to automatically create instances of case classes etc. for feeding them into tests. There is a library called scalacheck http://scalacheck.org/ that can be used for something like this. It provides generators for primitive types and mechanisms to derive generators for complex types. However, I think it has a focus on immutability and type safety and therefore is designed in a different way than what you might expect. – Rüdiger Klaehn Feb 18 '15 at 09:43

7 Answers7

10

There is a project called Fixture-Factory(https://github.com/six2six/fixture-factory). It was based in the Factory-Girl's idea.

You could easily create your object's template definition:

Fixture.of(Client.class).addTemplate("valid", new Rule(){{
  add("id", random(Long.class, range(1L, 200L)));
  add("name", random("Anderson Parra", "Arthur Hirata"));
  add("nickname", random("nerd", "geek"));
  add("email", "${nickname}@gmail.com");
  add("birthday", instant("18 years ago"));
  add("address", one(Address.class, "valid"));
}});

And then you can easily use it in your tests:
Client client = Fixture.from(Client.class).gimme("valid");

Nykolas Lima
  • 140
  • 1
  • 10
3

I created a new java framework Factory Duke to provide the same feature as Factory_Girl https://github.com/regis-leray/factory_duke

Really easy to use, define a template (in this case the default)

FactoryDuke.define(User.class, u -> {
    u.setLastName("Scott");
    u.setName("Malcom");
    u.setRole(model.Role.USER);
});

And use it

User user = FactoryDuke.build(User.class);

Please read the document to see advanced features

Regis dev
  • 31
  • 5
1

I wrote (and published) a library for defining object factories: https://github.com/arosini/wildstyle-generator

First you define and register the generator / factory:

WildstyleGenerator.createObjectGenerator(Employee.class)
  .mapField("firstName", new FirstNameValueGenerator(true))
  .mapField("lastName", new LastNameValueGenerator(true))
  .mapField("yearsEmployed", 10)
  .mapField("hourlyWage", new DoubleValueGenerator(10.0, 100.0))
  .mapField("employeeType", new EnumValueGenerator(EmployeeType.class, true)) 
  .register();

Then you can use the generator / factory:

Employee employee = WildstyleGenerator.generate(Employee.class);

There are some more advanced features which you can read about on the project's homepage. Note assertions must be enabled or the library will not function properly.

Adam
  • 2,214
  • 1
  • 15
  • 26
1

There is a Beanmother library: https://github.com/keepcosmos/beanmother

That helps to create your various and complex objects super easily with fixtures for testing. Beanmother is a implementation of ObjectMother pattern and also fixture replacement tool.

Jaehyun Shin
  • 1,562
  • 14
  • 25
1

Another solution, very similar to factory-bot (new name for factory-girl) is topicusoverheid/java-factory-bot you can use this way:

Given a model for an Article and a User (getters and setters are omitted):

@Data
public class Article {
    private String title;
    private String content;
    private Date creationDate;
    private User author;
}

@Data
public class User {
    private String username;
    private String firstName;
    private String lastName;
    private String email;
}

You can define factories like


class ArticleFactory extends Factory<Article> {
    Map<String, Attribute> attributes = [
            title       : value { faker.lorem().sentence() },
            content     : value { faker.lorem().paragraph() },
            creationDate: value { faker.date().past(20, TimeUnit.DAYS) },
            author      : hasOne(UserFactory)
    ]
}

class UserFactory extends Factory<User> {
    Map<String, Attribute> attributes = [
            username : value { faker.name().username() },
            firstName: value { faker.name().firstName() },
            lastName : value { faker.name().lastName() },
            email    : value { "${get("firstName")}.${get("lastName")}@example.com" }
    ]
}

And create objects using

Article article = new ArticleFactory().build()
which generates an article with default random but sane attributes. Individual attributes or relations can be overriden by passing them in a map:

Article article = new ArticleFactory().build([title: "Foo", user: [username: "johndoe"]])
0

Mockito has a mode where it will recursively return dynamically generated mock objects. If you need to do very sophisticated mocking (e.g. of construction or of static methods), you can use PowerMock to provide it, at the cost of doing bytecode manipulation.

But I urge you to consider more idiomatic approaches, rather than trying to write "Ruby/Python in Java/Scala" - there's no point in learning a language that doesn't change the way you think. You /should/ be taking advantage of the type system to ensure correctness, removing the need for many kinds of tests. You should be exposing a small interface which is inherently friendly to "traditional" mocking (i.e. using Easymock or Mockito in its default mode), or even manual stubbing. Particularly in scala, look to something like http://michaelxavier.net/posts/2014-04-27-Cool-Idea-Free-Monads-for-Testing-Redis-Calls.html (Haskell, but the idea is the same) to allow you to write higher-level tests that provide very strong guarantees about what your methods are doing.

lmm
  • 17,386
  • 3
  • 26
  • 37
  • It is not about writing Ruby in Java. It is about bringing good ideas from some language to another language. – Andi Dec 12 '18 at 10:15
  • It's important to consider the context of the language that lead to those ideas. What's a good idea in one language can easily be a bad idea in another. – lmm Dec 13 '18 at 19:48
0

There is Fritter Factory library: https://github.com/equinox-one/fritterfactory

A basic sample:

FritterFactory fritterFactory = new FritterFactory();
List<Person> persons = fritterFactory.buildList(Person.class, 3);

A sample with model customization:

FritterFactory fritterFactory = new FritterFactory();
MapMold personMold = new MapMold();
personMold.put(PersonSymbols.NAME, new FirstNameProvider());
personMold.put(PersonSymbols.SURNAME, new FirstNameProvider());
ModelProvider<Person> personProvider = new ModelProvider<Person>(fritterFactory, Person.class, personMold);
fritterFactory.addProvider(Person.class, createPersonProvider(fritterFactory));
List<Person> persons = fritterFactory.buildList(Person.class, 3);

An interesting thing of this library is that it can be used in Android too.

Mateu
  • 2,636
  • 6
  • 36
  • 54