nomemory/mockneat

subsequent run data consistency

asethia opened this issue · 2 comments

Thanks a lot for making such an excellent Mockneat library. We have a requirement where every time (subsequent run) the application should generate the same data from the MockNeat. Please let me know if MockNeat supports such features.

I tested the following code

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.andreinc.mockneat.MockNeat;
import net.andreinc.mockneat.types.enums.RandomType;

import java.util.List;

public class TestApp {

  public static void main(String[] args) {

    MockNeat m = new MockNeat(RandomType.SECURE,8L);

    List<Date1> date = m.reflect(Date1.class)
            .field("dateId",m.intSeq().start(1).increment(1))
            .field("year",m.ints().range(2000, 2019))
            .field("month",m.months().mapToString())
            .field("day",m.ints().range(1, 28))
            .list((int) 10)
            .val();

    Gson gson = new GsonBuilder().create();
    System.out.println(gson.toJson(date));

  }
}

public class Date1 {

  private Integer dateId;
  private Integer year;
  private String month;
  private Integer day;

  public Integer getDateId() {
    return dateId;
  }
  public void setDateId(Integer dateId) {
    this.dateId = dateId;
  }
  public Integer getYear() {
    return year;
  }
  public void setYear(Integer year) {
    this.year = year;
  }
  public String getMonth() {
    return month;
  }
  public void setMonth(String month) {
    this.month = month;
  }
  public Integer getDay() {
    return day;
  }
  public void setDay(Integer day) {
    this.day = day;
  }

  public Date1() {

  }
}

When I run this code , in each subsequent run I always find one record is not matching with old set of record.

@asethia

That's something not easy to implement unfortunately.

The solution is to generate data, serialise() it to a file and then read it everytime from the file.

First thing is to make the Date1 class serialisable:

public class Date1 implements Serializable {

And then the rest of the code looks like this:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

import static java.nio.file.Files.exists;
import static net.andreinc.mockneat.unit.objects.Filler.filler;
import static net.andreinc.mockneat.unit.seq.IntSeq.intSeq;
import static net.andreinc.mockneat.unit.time.Months.months;
import static net.andreinc.mockneat.unit.types.Ints.ints;

public class TestApp {

    public static final String datesPath = "dates.obj";

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        List<Date1> dates1 = getDates();
        List<Date1> dates2 = getDates();

        System.out.println(dates1);
        System.out.println(dates2);
    }

    public static List<Date1> getDates() throws IOException, ClassNotFoundException {

        Path path = Paths.get(datesPath);

        if (!exists(path)) {

            // If the data wasn't yet generated, generate it and store it in "dates.obj"
                filler(Date1::new)
                    .setter(Date1::setDateId, intSeq().start(1).increment(1))
                    .setter(Date1::setYear, ints().range(2000, 2019))
                    .setter(Date1::setMonth, months().mapToString())
                    .setter(Date1::setYear, ints().range(1, 28))
                    .list(10)
                    .serialize(datesPath);
        }

        // Read the already-generated data
        FileInputStream fis = new FileInputStream(datesPath);
        ObjectInputStream ois = new ObjectInputStream(fis);
        List<Date1> result = (List<Date1>) ois.readObject();
        return result;
    }
}

Now, you can see in the output that the values are identical:

[Date1{dateId=1, year=5, month='JUNE', day=null}, Date1{dateId=2, year=4, month='SEPTEMBER', day=null}, Date1{dateId=3, year=11, month='JULY', day=null}, Date1{dateId=4, year=6, month='MAY', day=null}, Date1{dateId=5, year=9, month='JANUARY', day=null}, Date1{dateId=6, year=18, month='JULY', day=null}, Date1{dateId=7, year=8, month='JUNE', day=null}, Date1{dateId=8, year=27, month='DECEMBER', day=null}, Date1{dateId=9, year=22, month='APRIL', day=null}, Date1{dateId=10, year=24, month='JUNE', day=null}]
[Date1{dateId=1, year=5, month='JUNE', day=null}, Date1{dateId=2, year=4, month='SEPTEMBER', day=null}, Date1{dateId=3, year=11, month='JULY', day=null}, Date1{dateId=4, year=6, month='MAY', day=null}, Date1{dateId=5, year=9, month='JANUARY', day=null}, Date1{dateId=6, year=18, month='JULY', day=null}, Date1{dateId=7, year=8, month='JUNE', day=null}, Date1{dateId=8, year=27, month='DECEMBER', day=null}, Date1{dateId=9, year=22, month='APRIL', day=null}, Date1{dateId=10, year=24, month='JUNE', day=null}]

Important:

  • Running the same code on different machines it will result in different data;
  • You need to be sure the writing location of the files is available;
  • I don't recommend using reflect() when you can use filler() instead;

Also, in the latest versions of the library some things have changed (for example you don't need to define the MockNeat object). Check the tutorial for new ways of working with the library: https://www.mockneat.com/tutorial/

Hope it helps.

Andrei

thanks @nomemory . We are using mockrneat with Scala code and dynamic bean/objects. I will find try to find out how I can use filler. We are still looking to generate the same data in the subsequent run, without storing them in file/serialized format.

I tried to use different RandomType, SecureRandom.getInstance("SHA1PRNG"), and It is generating the same data in the subsequent run, need to test more on different machines and OS.

public enum RandomType {


    OLD(new Random()),
    SECURE(new SecureRandom()),
    SECURETEST(getNewRandom()),
    THREAD_LOCAL(ThreadLocalRandom.current());

    private final Random random;

    RandomType(Random random) {
        this.random = random;
    }

    private static SecureRandom getNewRandom() {
        SecureRandom ret=null;
        try{
            ret=SecureRandom.getInstance("SHA1PRNG");
        }catch (Exception ex){
            ret = new SecureRandom();
        }
        return ret;
    }


    public Random getRandom() {
        return random;
    }
}