0

I've been tasked with creating a test to run against our Constants class to ensure that each value in the class is unique. I'm not talking about the constant names (the IDE will tell the developer if those are dup'd) but rather the values that the constants are being set to.

I'm new to Java and am unsure of how to go about doing this.

To be clear, my Constants class is defined as follows:

public static final String STATUS_RECEIVED = "RE";
public static final String STATUS_CANCELLED = "CA";
public static final String STATUS_REVIEWED = "RE";

In the above example, I would want my test to note that there is a value being duplicated (since STATUS_RECEIVED == STATUS_REVIEWED). How would I do this programmatically?

acedanger
  • 1,197
  • 2
  • 15
  • 34
  • 2
    If your constants need to be unique, you are probably using them as some sort of enumeration. You may want to use an enum for the possible values. This will not compile with duplicate entries, just like the compiler catches duplicated constant names. Just a thought... – Jesse Webb Apr 18 '12 at 17:39

6 Answers6

2

Iterate through all the constants' string values, and stick them in a set if they are not already in the set. If they are in the set already, then the tests fails.

Alternatively you could then stick the duplicates into a different set, and test on that set of duplicates being empty - that would give you a list of the duplicates each time you run the test (rather than having to re-run the test until you've removed all the duplicates).

amaidment
  • 6,942
  • 5
  • 52
  • 88
2
Field[] fields = Constants.class.getDeclaredFields();
List<Field> staticFields = new ArrayList<>();
for(Field f:fields) {
  if (Modifier.isStatic(f)) {
    staticFields.add(f);
  }
}
for (int i = 0; i < staticFields.size(); i++) {
  for (int j = i + 1; j < staticFields.size(); j++) {
    if (staticFields.get(i).get(null).equals(staticFields.get(j).get(null))) {
      throw new AssertionFailedError(staticFields.get(i) + " equals " 
        + staticFields.get(j));
    } 
  }
}
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • Awesome! The first line is a great kick starter for me. Thanks for the code. – acedanger Apr 18 '12 at 17:42
  • @acedanger This is a great solution for your current `Constants` class. However I'd still strongly recommend that you use enums instead, your use case is exactly what they're designed for. – darrengorman Apr 18 '12 at 18:00
  • I really appreciate the recommendation. I'll discuss it with the project leads. – acedanger Apr 18 '12 at 18:04
1

You can just discover the fields and then check for uniqueness (e.g. put them in a treemap, then count).

public void test() throws Exception {
    for (Field f : ConstantsClass.class.getDeclaredFields()) {
        System.out.println(f.getName() + ": " + f.get(null));
    }
}

Taken from Accessing Java static final ivar value through reflection

Community
  • 1
  • 1
j13r
  • 2,576
  • 2
  • 21
  • 28
1

Use java.lang.Class.getFields(), iterate through the array, get each value (using Field.get(null)), check if it's already in a Set, and store it in the Set if it's not there already.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
0

Your life would be a lot easier if you were to use an enum instead. You would then have a choice between making the member names match the required values

enum Status {
RE,CA,RE;
}

in which case the compiler guarantees them to be unique, or storing the value as a property

enum Status {
  averbosenamedescribingwhatremeans("RE") 
  etc, etc

  private final String statusCode;

  Status(String code) {
  this.statusCode = code;
  }  
}

You would be easily able to check for the uniqueness of codes within a unit test using the values() method provided by enums.

Plus you would have type safe code.

With your current approach you would need to query the class via reflection.

henry
  • 5,923
  • 29
  • 46
0

Consider making Constants an Enum holding the current String value. Something like:

public enum Constants {

    STATUS_RECEIVED("RE"),
    STATUS_CANCELLED("CA"),
    STATUS_REVIEWED("RE")

    private String value;

    public Constants(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

Then your test could iterate over the value field of each Enum constant and fail if that value already exists For example:

public void testConstantValueUniqueness() {
    Set<String> values = new HashSet<String>();
    for(Constants constant : Constants.values()) {
        if(values.contains(constant.getValue())) {
            // fail
        }
        values.add(constant.getValue());
    }
}
darrengorman
  • 12,952
  • 2
  • 23
  • 24