3

Assuming in a unit test I need to have an object all of 50 fields of which are set up with some values. I don't want to manually set up all this fields, as it takes time and annoying...

Somehow I need to get an instance where all the fields are initialized by some not-null values.

and I had an idea - what if I will debug some code, at some point i will get a working instance of this object with some data set up - and I just will serialize it to the disk.

Then I will put this file to test-resources folder, and in unit tests will just deserialize it from that location.

Sounds feasible.. and reasonable? Is there any other idea, or how would you do that?

UPD: I agree serialization is not good in that case. 1) Saved object is not human readable 2) Version could change (highly unlikely) and is not a big problem I believe... So, maybe are there any readable easy-for-serialization formats?

Ideally I would like to have actually source code to be generated. Because it is a java bean, all the getters/setters are there. Why not generate the set of setters calls over the given object in runtime?

javagirl
  • 1,635
  • 6
  • 27
  • 43

3 Answers3

1

This problem has been solved: https://github.com/bbottema/lorem-ipsum-objects

Benny Bottema
  • 11,111
  • 10
  • 71
  • 96
HiJon89
  • 891
  • 6
  • 6
0

It will work but it's Nasty with a capital N.

The problem is, when somebody reads the code it's hard to see just what values are being used - given code is read many more times than it's written you should optimise for reading.

Other things that spring to mind:

  • testing is all about the boundaries, if you're just using a single set of values, how can your test hit those boundaries?
  • does every test need all 50 values, is so there could be something else wrong with your design

If all 50 values do need setting in every test, a common way to make it easier is to use a factory method or the builder pattern - each sets sensible defaults and allows you to override just the values you need.

Nick Holt
  • 33,455
  • 4
  • 52
  • 58
  • 1
    yes, that was the idea - to set the needed defaults and override "boundaries" . also objects can be the same, but "boundaries" could be outside that object, and this also has to be tested - how system reacts to the same object but in different environments. the problem is in this factory method. Who should write that? I don't want to. I's annoying, and moreover I'm not sure about which values are defaults. If serialization is baaaad - can it be possible to generate that factory method by giving the object instance as input? You right that code has to be readable... – javagirl May 02 '13 at 11:11
  • Part of development is that sometimes you have to do tedious tasks, but the clarity of the code outweighs your temporary tedium - in this case the person writing the test has to write the method. Some of the mocking APIs will return defaults in response to method calls that you haven't declared but this just sounds like complexity to me - the simplest thing that works is to initialize the object in the test case for all to see. – Nick Holt May 02 '13 at 11:43
  • 1
    but this is stupid.. object contains a lots of fields, and I dont even know what are valid values for some of the fields.. i just need typical object with preset values. i don't believe there is no such tool to generate java code over given java bean instance with all the setters/getters defined. Seems like my question is similar to http://stackoverflow.com/questions/3251190/how-do-i-generate-the-source-code-to-create-an-object-im-debugging – javagirl May 02 '13 at 11:48
  • In this situation, I normally set the fields I need and run my test. If that fails, I work out which additional fields need setting and set those too. It's unlikely you need all 50 fields for your first test, but as you add more tests all the fields slowly get populated. – Nick Holt May 02 '13 at 11:53
  • 1
    I don't know which fields I will need, which are required, which are not. Moreover, there are some implicit constraints like .. if some field set to be "FX", a lot of another fields has to be set up. The amount of iterations "set one field, run test, it fails, repeat from step 1" couuld easily exceed any reasonable figure... btw, there are 190 fields, just counted ... – javagirl May 02 '13 at 12:04
0

Why don't you create a .properties file with the property name exactly as same as your attribute in the class. Read this properties file key/values and call setters using the key by reflection. Here is a basic sample code for doing so:

package consoleouput;

import java.io.FileInputStream; import java.lang.reflect.Method; import java.util.Properties; import java.util.Set;

class Config {  private String a;   private String b;

    public String getA() {      return a;   }

    public void setA(String a) {        this.a = a;     }

    public String getB() {      return b;   }

    public void setB(String b) {        this.b = b;     }

}

public class App {  public static void main(String[] args) {        Properties prop = new Properties();         Config config = new Config();       try {           // load a properties file           prop.load(new FileInputStream("config.properties"));            Set<Object> propKeys = prop.keySet();           for (Object key : propKeys) {
                String keyString = (String) key;
                String keyValue = prop.getProperty((String) key);
                // Make sure you use the key value starting with upper case in
                // properties file
                String keySetterMethod = "set" + keyString;
                System.out.println("Setter method name :" + keySetterMethod);
                // Use reflection to call the method
                Method method = config.getClass().getMethod(keySetterMethod,
                        String.class);

                method.invoke(config, keyValue);            }           System.out.println("Value of a : " + config.getA());            System.out.println("Value of b : " + config.getB());        } catch (Exception e) {             e.printStackTrace();        }   } }

Here is the sample cofig.properties content :

A=test B=rest

NOTE :You may use a csv for generating different objects using the same approach.

Juned Ahsan
  • 67,789
  • 12
  • 98
  • 136