Pain points of testing

Hello, I’m Ma.

Most of every developer’s job is to write code, test code, and fix bugs.

We have a lot of test code, and it takes a lot of practice to build an object.

So I was thinking, can I fill an object automatically?

So I went to Github and found a test artifact called data-Factory.

Github.com/houbb/data-…

data-factory

role

The data-factory project is used to randomly and automatically generate initialization information based on objects. Easy to test.

features

  • Eight basic types are supported

  • Arrays, objects, enumerations, maps, linked lists, sets, and more are supported

  • Support for common types such as String, BigDecimal, BigInteger, Currency, etc

  • Date, LocalDate, LocalDateTime, LocalTime, and Year are supported

  • Support for Regex regular expressions

  • @datafactory Annotations support flexible configuration

Quick start

Introduction of depend on

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>data-factory-core</artifactId>
    <version>0.0.8</version>
</dependency>
Copy the code

Datautil.build (class) generates a random value for the corresponding class.

Such as DataUtil. Build (String. Class); To generate a random string:

0s5Z8foS1
Copy the code

Ma found it convenient to specify a class for all common types.

But I usually work with objects, so can I automatically populate an object?

Object Bean population

The most common, of course, is to initialize a Java object.

public class User {

    private String name;

    private int age;

    private Date birthday;

    private List<String> stringList;

    / / S/F of the enumeration
    private StatusEnum statusEnum;

    private Map<String, String> map;
    
    //Getter & Setter
}
Copy the code

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

Build objects as follows:

User{name='wZ8CJZtK', age=-564106861, birthday=Wed Feb 27 22:14:34 CST 2019, stringList=[Du4iJkQj], statusEnum=S, map={yA5yDqM=Kdzi}}
Copy the code

The content is random each time, making it easy to populate basic test data.

@DataFactoryannotations

Of course, there are times when we want the generated data to conform to certain rules, and this can be restricted by the @Datafactory annotation.

Annotation properties

/** * Data generation annotation *@author binbin.hou
 * @date 2019/3/9
 * @sinceHundreds * /
@Inherited
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataFactory {

    /** * Whether to ignore this field **@return*/ is not ignored by default
    boolean ignore(a) default false;

    /** * Number Specifies the maximum number of integers. * Only fields of numeric type * *@returnReturns the maximum value */
    int max(a) default 100;

    /** * The smallest part of a numeric integer. * Only fields of numeric type * *@returnReturns the minimum value */
    int min(a) default 0;

    /** * precision. * Works on Float, Double, BigDecimal fraction length * *@returnReturn precision */
    int precision(a) default 2;

    /** * Maximum length. Only fields of type String * *@returnReturns the maximum length */
    int maxLen(a) default 30;

    /** * Minimum length. Only fields of type String * *@returnReturns the minimum length */
    int minLen(a) default 1;

    /** * Specifies the class implementation policy * for the current field@returnThe implementation class *@since0.0.6 * /
    Class<? extends IData> data() default IData.class;

    /** * regular expressions * 1. For simplicity, the current version ignores length, precision, and other annotation configurations if regex exists. 3. If you use other types, you must ensure that the corresponding String constructor is provided. Such as {@linkLong#Long(String)} * 4. Base types will use the corresponding wrapper type directly. *@since 0.0.3
     * @returnExpression information */
    String regex(a) default "";

}
Copy the code

The String class

  • Define the object
/** * string class annotation test *@author binbin.hou
 * @date 2019/3/9
 * @sinceHundreds * /
public class UserAnnotationString {

    /** * specifies the minimum length and the maximum length */
    @DataFactory(minLen = 2, maxLen = 10)
    private String name;

    /** * ignores generating the current field */
    @DataFactory(ignore = true)
    private String hobby;

    //Getter & Setter

}
Copy the code
  • The test code
/**
*
* Method: build(clazz)
*/
@Test
public void stringAnnotationTest(a) throws Exception {
    for(int i = 0; i < 100; i++) {
        UserAnnotationString userAnnotationString = DataUtil.build(UserAnnotationString.class);

        Assertions.assertNull(userAnnotationString.getHobby());
        Assertions.assertTrue(userAnnotationString.getName().length() >= 2);
        Assertions.assertTrue(userAnnotationString.getName().length() <= 10); }}Copy the code

Number class

  • Object definitions
/** * number class annotation test *@author binbin.hou
 * @date 2019/3/9
 * @sinceHundreds * /
public class UserAnnotationNumber {

    @DataFactory(min = 10, max = 20)
    private Byte aByte;

    @DataFactory(min = 10, max = 20)
    private Short aShort;

    @DataFactory(min = 10, max = 20)
    private Integer integer;

    @DataFactory(min = 10, max = 20)
    private Long aLong;

    @DataFactory(min = 10, max = 20, precision = 3)
    private Double aDouble;

    @DataFactory(min = 10, max = 20, precision = 3)
    private Float aFloat;

    @DataFactory(min = 10, max = 20, precision = 3)
    private BigDecimal bigDecimal;

    @DataFactory(min = 10, max = 20)
    private BigInteger bigInteger;

    //Getter & Setter

}
Copy the code
  • The test code

Through DataUtil. Build (UserAnnotationNumber. Class) generated object is as follows:

UserAnnotationNumber{aByte=10, aShort=17, INTEGER =19, aLong=11, aDouble=19.888, sticker =10.067, bigDecimal=18.035, bigInteger=13}Copy the code

Regular expression

Regular expressions are a great tool that can’t be left behind.

define

The object is defined as follows:

/** * Regular expression test object *@author binbin.hou
 * @date 2019/3/12
 * @since0.0.3 * /
public class RegexBean {

    @ the DataFactory (regex = "[0, 3], [c] a - | - g [e]} {1, 2)")
    private String name;

    @ the DataFactory (regex = "[0-9] {1, 2}")
    private int age;

    @ the DataFactory (regex = "[0-9] {1, 2}")
    private BigDecimal amount;

    //Getter & Setter
    
}
Copy the code

The effect

The result is as follows:

RegexBean{name='2c', age=61, amount=39}
Copy the code

Customize the Data generation policy

Of course, all built-in policies only meet the most common requirements.

However, there are no specific customization strategies available, and fortunately we can customize our own data populating strategy.

Customize the generation policy

Here we implement the simplest generation strategy, which is set to 123 if it is a string.

public class MyStringData implements IData<String>  {

    @Override
    public String build(IContext context, Class<String> stringClass) {
        return "123"; }}Copy the code

use

We specify our policy in the @Datafactory annotation.

public class UserAnnotationData {

    @DataFactory(data = MyStringData.class)
    private String name;

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name; }}Copy the code

The result is our own data generation strategy.

Deficiency in

Of course, Ma found these features inconvenient.

Hopefully the authors can implement features such as support for global configuration, which would be more convenient.

Friends can also experience, let yourself leave work early, enjoy their own time.

summary

Today we experienced the convenience of data filling tools, which you can use when you need them in your work.

For your convenience, all source code is open source:

Object filling: github.com/houbb/data-…

Performance pressure measurement: github.com/houbb/junit…

I hope this article is helpful to you. If you like it, please click to collect and forward a wave.

I am an old horse, looking forward to meeting with you next time.