A library for setting up Java objects as test data.

Overview

Beanmother

Maven Central Build Status Coverage Status Javadocs License

beanmother

Beanmother helps to create various objects, simple and complex, super easily with fixtures for testing. It encourages developers to write more tests.

Beanmother is an implementation of ObjectMother pattern and also fixture replacement tool. You do not need to write extra code(like factories or builders) for creating test objects. Beanmother helps to create fresh and randomized bean objects for every type of test. You can use a bean as is!.

Java 7 and above are supported.

Example

Create fixture .yml file in test/resources/fixtures as a convention.

# test/resources/fixtures/publishing.yml

book: &book
  title: ${faker.book.title}
  language: en
  publishedAt: ${faker.date.between('2000-01-01', '2010-01-01')}

author:
  id: ${sequence.number}
  name: Ernest Hemingway
  introduction: ${faker.lorem.paragraph}
  birth: July 21, 1899
  gender: MALE
  works:
    - <<: *book
    - <<: *book
    - <<: *book

YAML format is very easy to read and write. It is expressive and extensible as well. You can use scripts provided by Beanmother to create multiple types of random data and global sequential numbers.

ObjectMother objectMother = ObjectMother.getInstance();

@Test
public void testSingleObject() {
    Book book = objectMother.bear("book", Book.class);
    Author author = objectMother.bear("author", Author.class);    
}

@Test
public void testMultipleObjects() {
    List<Author> authors = objectMother.bear("author", Author.class, 10);
}

And just create!

But if for some reason, you need load the fixtures from another directory inside the classpath

objectMother.addFixtureLocation("another_dir") // test/resources/another_dir

And if the directory it's outside classpath

objectMother.addFixtureLocation("filesystem:///absolute/path/to/fixture/dir") // /absolute/path/to/fixture/dir 

Usage

Installation

  • Apache Maven
<dependency>
    <groupId>io.beanmother</groupId>
    <artifactId>beanmother-core</artifactId>
    <version>0.9.0</version>
    <scope>test</scope>
</dependency>
  • Gradle
testCompile 'io.beanmother:beanmother-core:0.9.0'

Extensions

Fixture Script

The scripts provided by Beanmother are kind of fake property value generators.

author:
  title: ${faker.book.title}

Currently, FakerScriptRunner and SeqenceScriptRunner are registered as a default.

  • FakerScriptRunner works with faker namespace. The script runner is implemented by java-faker. You can find a usage of java-faker in this document. If a method has no arguments, parentheses can be ignored. For example,
beer:
  hop: ${faker.beer.hop}
  malt: ${faker.beer.malt}
  created_at: ${faker.date.between('1990-01-01', '2000-01-01')}
  • SequenceScriptRunner works with the sequence namespace. The script generates sequential numbers globally. For example,
person:
  id: ${sequence.number}

Arguments constructor bean

If a bean does not have a no-argument contructor, just add _construct key. For example,

price:
  _construct:
    - 3
    - USD

PostProcessor

If you need a common configuration for specific beans, you can use PostProcessor.

Customization

ObjectMother class is a default implementation of AbstractBeanMother class. For customization, simply extend AbstractBeanMother. I highly recommend building it as a singleton instance.

public class MyObjectMother extends AbstractBeanMother {

    private static MyObjectMother myObjectMother = new MyObjectMother();

    private MyObjectMother() {
        super();
    }


    // Override for adding your default fixture directory paths.
    @Override
    public String[] defaultFixturePaths() {
        return new String[]{ 'test-models', 'fixtures' };
    }

    // Override for adding your custom Converter.
    @Override
    protected void configureConverterFactory(ConverterFactory converterFactory) {
        converterFactory.register(new MyConverter());
    }

    // Override for adding your custom ScriptRunner.
    @Override
    protected void configureScriptHandler(ScriptHandler scriptHandler) {
        scriptHandler.register(new MyScriptRunner);     
    }

    // Override for adding your custom PostProcessor.
    @Override
    protected void configurePostProcessorFactory(PostProcessorFactory postProcessorFactory) {
        postProcessorFactory.register(new MyPostProcessor);
    }
}

Register PostProcessors

A PostProcessor can handle your bean after mapper.

public class AuthorPostProcessor extends PostProcessor<Author> {
    @Override
    public void process(Author bean, FixtureMap fixtureMap) {
        for(Book book : bean.getWorks()) {
            book.setAuthor(bean);
        }
    }
}

And, pass the instance as an argument when you create an instance.

Author author = ObjectMother.bear("author", Author.class, new AuthorPostProcessor());

or, register the PostProcessor to your custom BeanMother for using it globally.

@Override
protected void configurePostProcessorFactory(PostProcessorFactory postProcessorFactory) {
    postProcessorFactory.register(new AuthorPostProcessor());
}

Everytime you create an instance of Author, AuthorPostProcessor will run before returning an instance of Author.

Customize default fixture path.

Just register the path in ObjectMother. It will scan all files under the path.

ObjectMother.addFixtureLocation("mocks");

Or, override #defaultFixturePaths in your custom BeanMother.

@Override
public String[] defaultFixturePaths() {
    // Add your fixture directory or file paths under `resources`.
    return new String[]{ 'test-models', 'fixtures' };
}

Customize converter

You can write your own converter if you want to.

public class MyIntegerToStringConverter extends AbstractGenericConverter<Integer, String> {
    @Override
    public String convert(Integer source) {
        return String.valueOf(source + 1);
    }
}

And, register the converter in your custom BeanMother.

@Override
protected void configureConverterFactory(ConverterFactory converterFactory) {
    converterFactory.register(new MyIntegerToStringConverter());
}

Customize ScriptRunner

You can write your own ScriptRunner.

public class MyScriptRunner implements ScriptRunner {

    @Override
    public Object run(ScriptFragment scriptFragment) {
		    // Do something
        return any;
    }

    @Override
    public boolean canHandle(ScriptFragment scriptFragment) {
        return scriptFragment.getMethodName.equal("myname");
    }
}

And, register the ScriptRunner in your custom BeanMother.

@Override
protected void configureScriptHandler(ScriptHandler scriptHandler) {
    scriptHandler.register(new MyScriptRunner());     
}

Tests

$ mvn test

Contributions

Any kind of contributions are very welcome! Coding style guideline is not prepared yet. Although I use Intellij IDE default style, follow common sense and please use four-space indentation.

Comments
  • Singlepageintro

    Singlepageintro

    Hi @keepcosmos ,

    Created single HTML page with README.md content and navigation as per given reference links.

    Please check and accept the Pull request

    opened by bhaskarmac 24
  • First approx to get a fixture to invoke a builder method of class to

    First approx to get a fixture to invoke a builder method of class to

    I'm trying to use with bean create by gRPC (google protobuffer) that has no public constructor because implement by its self a builder pattern...

    I saw the option to "Arguments constructor bean", but not the option to invoke the builder method.

    It's a simple pull request that implements this fixture.

    opened by josejuanmontiel 15
  • It throws a UnsupportedOperationException when there is no default constructor.

    It throws a UnsupportedOperationException when there is no default constructor.

    I am trying to create an instance of a object that is annotated with @Builder from lombok.Builder It throws an java.lang.UnsupportedOperationException saying that the object has no default constructor.

    Is it possible to add a new feature to create the object with All args constructor ?

    opened by vishwa- 6
  • Query

    Query

    1. Is it possible to create a bean object for an object which is not at the root level? Ex:
    my:
      book: &book
        id: ${sequence.number}
        title: ${faker.book.title}
        language: en
        publishedAt: ${faker.date.between('2000-01-01', '2010-01-01')}
    
      author:
        id: ${sequence.number}
        works:
          - <<: *book
          - <<: *book
          - <<: *book
        somethingElse: bla
    
    1. Is it possible to create a bean for a specific object in a specific file if there are duplicate yaml objects. Ex:
    first.yml
    book: &book
      id: 1
      title: ${faker.book.title}
      language: en
      publishedAt: ${faker.date.between('2000-01-01', '2010-01-01')}
    

    and

    second.yml
    book: &book
      id: 2
      title: ${faker.book.title}
      language: en
      publishedAt: ${faker.date.between('2000-01-01', '2010-01-01')}
    
    opened by njchandu 4
  • improvements

    improvements

    • fixing tests on windows .. was getting java.nio.file.InvalidPathException: Illegal char <:> at index 2:
    • improved and corrected exception messages
    • dependency updates
    opened by gtiwari333 3
  • Doesn't support Set

    Doesn't support Set

    If target object has field of type Set, following exception is thrown

    io.beanmother.core.mapper.FixtureMappingException: Target setter of 'name-of-the-property' must be List or array.

    this method only checks for arrays or lists, because of that having custom converter doesn't resolve the problem.

    hacktoberfest feature 
    opened by ruwanka 3
  • Updating faker version to 0.15

    Updating faker version to 0.15

    This offers generating some additional faker data like

    • Internet.uuid()
    • Weather and few others

    https://github.com/DiUS/java-faker/compare/javafaker-0.14...master https://github.com/DiUS/java-faker/compare/javafaker-0.15...master

    opened by njchandu 2
  • How to query

    How to query

    This is a how to query. Apologies if this is not the right place to post queries:

    book: &book
      id: ${sequence.number}
      title: ${faker.book.title}
      publishedAt: &anchor_val2 ${faker.date.between('2000-01-01', '2010-01-01')}
    
    author:
      id: ${sequence.number}
      policies:
        id1:
          id: ${sequence.number}
          title: ${faker.book.title}
          publishedAt: *anchor_val2
        id2:
          id: ${sequence.number}
          title: ${faker.book.title}
          publishedAt: ${current.date}
    

    Using yaml anchors here, publishedAt: *anchor_val2 generates new ${faker.date.between('2000-01-01', '2010-01-01')}

    Is there a way I can reference (reuse) the data generated in publishedAt: &anchor_val2 ${faker.date.between('2000-01-01', '2010-01-01')}

    opened by njchandu 2
  • Create a introduction single page.

    Create a introduction single page.

    Add a single and static html page for introduction in /docs path. The Introduction should be from README.md

    for example)

    • http://joel-costigliola.github.io/assertj/
    • http://natty.joestelmach.com/
    hacktoberfest 
    opened by keepcosmos 2
  • Is it possible to use Pair object to translate the yml data

    Is it possible to use Pair object to translate the yml data

    author:
      id: ${sequence.number}
      policies:
        id2:
          id: ${sequence.number}
          title: ${faker.book.title}
          pubInfo:
            publishedAt: ${current.date}
            publishedAt: ${faker.date.between('2020-01-01', '2030-01-01')}
    

    Is it possible to translate it to

    private Pair<String, Book> policies;
    

    I'm able to read it into a map though.

    private Map<String, Book> policies;
    

    Thanks in advance!

    opened by njchandu 1
  • Bump snakeyaml from 1.23 to 1.26 in /beanmother-core

    Bump snakeyaml from 1.23 to 1.26 in /beanmother-core

    Bumps snakeyaml from 1.23 to 1.26.

    Commits
    • 9801cc7 Refactor: improve AliasEvent processing
    • a2066e3 Refactor Events: expose Event.ID via a getter
    • 72976f6 Merge
    • 03acd6b Add test for not implemented "!" tag
    • a122a5b Decide not to fix issue 459
    • 952f977 Serializer: release unused resources when closed
    • ccd45df Yaml: improve Javadoc
    • b56ada6 merge
    • bcb8a58 Clean up composer resources
    • 289c35a Apply Sonar improvements
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump snakeyaml from 1.26 to 1.32 in /beanmother-core

    Bump snakeyaml from 1.26 to 1.32 in /beanmother-core

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • build instance of an class which reference another class

    build instance of an class which reference another class

    in the lombok builder pattern, how to build instance of a target class which reference another class instance?

    class  A {
        private String fieldA;
    }
    
    @Data
    @Builder
    class B {
        private String fieldB;
        private A a;
    }
    `
    
    appreciate for any help~~
    opened by mashroomxl 0
  • Bump guava from 27.0.1-jre to 29.0-jre in /beanmother-core

    Bump guava from 27.0.1-jre to 29.0-jre in /beanmother-core

    Bumps guava from 27.0.1-jre to 29.0-jre.

    Release notes

    Sourced from guava's releases.

    29.0

    Maven

    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>29.0-jre</version>
      <!-- or, for Android: -->
      <version>29.0-android</version>
    </dependency>
    

    Javadoc

    JDiff

    Changelog

    • Guava types can no longer be sent over GWT-RPC. To temporarily reenable support, set the guava.gwt.emergency_reenable_rpc system property to true. (5214a10b1e)
      • This is the only breaking change in this release, and it affects only users of the guava-gwt artifact, not people who use only the guava artifact. This release contains no changes that break binary compatibility for any users.
    • API documentation for Guava classes is now easier to reach. For example, for ImmutableList, visit guava.dev/ImmutableList. Also, more easily access the index at guava.dev/api.
    • collect: Annotated FluentIterable.from(FluentIterable) with @DoNotCall. (b1c77b7df3)
    • collect: Made ceiling, floor, headSet(E, boolean), and tailSet(E, boolean) methods available in the GWT-emulated ImmutableSortedSet. (7e0fe90ca8, 5f2fbf27b2)
    • graph: Made it possible to set a stable incident edge order by calling the newly added method [Value]Graph.Builder.incidentEdgeOrder(ElementOrder.stable()). (70164025a8)
    • graph: Added incidentEdgeOrder() to the [Value]Graph interfaces. (cde576ec00)
    • util.concurrent: Added Duration-based default methods to ListeningScheduledExecutorService. (931e83f969)
    • util.concurrent: Added immediateVoidFuture. (9f3bae5853)
    • util.concurrent: Removed @Beta from Service and related classes. (dc46627fea)
    • util.concurrent: Deprecated the 1-arg overload of ServiceManager.addListener. (86e3620125)
    • util.concurrent: Changed the return type of ServiceManager.servicesByState() to ImmutableSetMultimap (but also retained a method with the old signature for binary compatibility). (31999ae6f5)
    • util.concurrent: Made it safe to load the AbstractFuture class from a ForkJoinPool thread under a security manager. (6e0c5b5d50)

    28.2

    Maven

    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>28.2-jre</version>
      <!-- or, for Android: -->
      <version>28.2-android</version>
    </tr></table> 
    

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Info question

    Info question

    Excellent tool again. I am using this for test data in a test project. Is there a way to read the values of the yaml file to a map of objects. Something like, map<Object, Object>?

    Because the test data can grow over time and the structure will never get complex. So, it can get to a max of 2 or 3 levels in hierarchy. I am open to suggestions if this approach doesn't make sense. Please recommend what makes sense.

    Thanks.

    opened by njchandu 0
  • enums: allow custom to string implementations

    enums: allow custom to string implementations

    As per the enum spec

    • name() is final and can't change. It refers to the exact defined name of the constant, as declared in the enum.
    • toString() is arbitrary and can be developer overridden. It defaults to name()

    So, this should use name() instead of toString(), in-case a developer (today, me) overrides the toString of an enum.

    Also removes some strange behaviour with _- in enums?

    opened by dirkredeye 0
Owner
Jaehyun Shin
Hi!
Jaehyun Shin
JUnit 5 Parameterized Test Yaml Test Data Source

Yamaledt — JUnit 5 Parameterized Tests Using Yaml and Jamal Introduction and usage Note This is the latest development documentation. This is a SNAPSH

Peter Verhas 4 Mar 23, 2022
Arbitrary test data generator for parameterized tests in Java inspired by AutoFixture.

AutoParams AutoParams is an arbitrary test data generator for parameterized tests in Java inspired by AutoFixture. Sometimes setting all the test data

null 260 Jan 2, 2023
Generator fake objects from a template

Fixture Factory is a tool to help developers quickly build and organize fake objects for unit tests. The key idea is to create specification limits of

six2six 423 Dec 15, 2022
A Java architecture test library, to specify and assert architecture rules in plain Java

ArchUnit is a free, simple and extensible library for checking the architecture of your Java code. That is, ArchUnit can check dependencies between pa

TNG Technology Consulting GmbH 2.5k Jan 2, 2023
AllPairs4J - an open source Java library for generation of minimal set of test combinations

AllPairs4J AllPairs4J is an open source Java library for generation of minimal set of test combinations. AllPairs4J is a Java port of allpairspy proje

Pavel Nazimok 5 Dec 11, 2022
Serenity BDD is a test automation library designed to make writing automated acceptance tests easier, and more fun.

That feeling you get when you know you can trust your tests Serenity BDD is a library designed to make writing automated acceptance tests easier, and

Serenity BDD 654 Dec 28, 2022
Never debug a test again: Detailed failure reports and hassle free assertions for Java tests - Power Asserts for Java

Scott Test Reporter for Maven and Gradle Get extremely detailed failure messages for your tests without assertion libraries, additional configuration

Dávid Csákvári 133 Nov 17, 2022
A sample repo to help you handle basic auth for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to handle basic auth for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - htt

null 12 Jul 13, 2022
A sample repo to help you run automation test in incognito mode in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to run automation test in incognito mode in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - htt

null 12 Jul 13, 2022
A sample repo to help you handle cookies for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to handle cookies for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - https:

null 13 Jul 13, 2022
A sample repo to help you set geolocation for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to set geolocation for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - https

null 12 Jul 13, 2022
A sample repo to help you capture JavaScript exception for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to capture JavaScript exception for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Wi

null 12 Jul 13, 2022
A sample repo to help you find an element by text for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to find an element by text for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows

null 12 Jul 13, 2022
A sample repo to help you emulate network conditions in Java-selenium automation test on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to emulate network conditions in Java-selenium automation test on LambdaTest Prerequisites Install and set environment variable for java. Windows

null 12 Jul 13, 2022
PowerMock is a Java framework that allows you to unit test code normally regarded as untestable.

Writing unit tests can be hard and sometimes good design has to be sacrificed for the sole purpose of testability. Often testability corresponds to go

PowerMock 3.9k Dec 28, 2022
PowerMock is a Java framework that allows you to unit test code normally regarded as untestable.

Writing unit tests can be hard and sometimes good design has to be sacrificed for the sole purpose of testability. Often testability corresponds to go

PowerMock 3.9k Dec 28, 2022
Enabling Test Automation in Java

SeLion Enabling Test Automation in Java SeLion builds on top of TestNG and Selenium to provide a set of capabilities that get you up and running with

PayPal 268 Dec 11, 2022
A simple yet powerful parameterized test runner for Java.

TestParameterInjector Introduction TestParameterInjector is a JUnit4 test runner that runs its test methods for different combinations of field/parame

Google 324 Dec 30, 2022