0

I have 0..n objects, each of which requires a unique identifier, that are created in this way:

public class Squirrel {

    private static numSquirrels = 0;

    private String id = null;

    public Squirrel() {
        this(String.valueOf(numSquirrels++);
    }

    public Squirrel(String id) {
        this.id = id;
    }
}

This is a problem in a few ways but I'll give one:

When unit testing, the numSquirrels variable carries over between tests, even though I may be working with a different population of squirrels. That means that their IDs continue to increment when I'd like to start fresh.

  • Is this the correct time to use a SquirrelFactory (the ones the kids are raving about)?
  • Should I pass the Factory into the Squirrel object using dependency injection, or should the Squirrel class be contained inside the Squirrel Factory which has an interface to the outside world?
  • How do I ensure uniqueness if I want the user to be able to set the ID (or at least suggest IDs)?
sdasdadas
  • 23,917
  • 20
  • 63
  • 148

6 Answers6

3

I think this implementation will work fine, although you should probably use AtomicInteger if you are dealing with concurrency.

Your unit testing problem can be solved using a combination of mocking and wrapping it in another class to mock. See this post How to mock a static variable in java using JMock

Alternatively, a simple solution would be to expose a setter for the static variable, in which at the end of your test cases, you can set it back to 0, or whatever "reset" means to you.

Community
  • 1
  • 1
75inchpianist
  • 4,112
  • 1
  • 21
  • 39
  • This will work for him except it doesn't allow checking for uniqueness of IDs – Stanley De Boer Feb 07 '13 at 19:26
  • how would you normally check for uniqueness and why doesn't this allow it? the setter would be used as a cleanup function for the testcase – 75inchpianist Feb 07 '13 at 19:30
  • I'm not sure if I quite understand this answer... I simply add a method for getting / setting the private static variable? – sdasdadas Feb 07 '13 at 19:35
  • 1
    yes, setup your junit so it does cleanup after each test. if you don't do this already, look here http://stackoverflow.com/questions/9903341/cleanup-after-all-junit-tests in your cleanup function, call the setter on your static variable to reset it to what it was before your test ran – 75inchpianist Feb 07 '13 at 19:42
  • I'm accepting this answer - it's not ideal for my situation, but it allows me to test without re-factoring in factories. – sdasdadas Feb 07 '13 at 19:45
0

Introduce a class called SquirellPopluation which will serve as a Squirrel factory, move the static counter to it, and make it instance variable.

If you want the user of the factory to be able to set their own id's then use a set instead of just a counter.

piokuc
  • 25,594
  • 11
  • 72
  • 102
  • Does the SquirrelPopulation get passed in to the Squirrel object or do I use SquirrelPopulation.createSquirrel()? – sdasdadas Feb 07 '13 at 19:10
0

You can have a static "reset" method for the class. Call it as part of the tear-down (or set-up) for the test.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
0

Squirrel class should probably not know about factory. I would suggest the following implementation:

public interface Squirrel // interface, not class
{
    public String getID ();

    // other methods here
}

public class SquirrelFactory
{
    private int nextSquirrelID = 0;

    public Squirrel createSquirrel ()
    {
        return new SquirrelImpl (String.valueOf (nextSquirrelID++));
    }

    private static class SquirrelImpl implements Squirrel
    {
        private final String id;

        // other fields here

        public SquirrelImpl (String id)
        {
            this.id = id;
        }

        @Overrides
        public String getID ()
        {
            return id;
        }

        // other methods here
    }
}

Then use method createSquirrel of a SquirrelFactory instead of constructor. And for each unit test create new instance of SquirrelFactory class.

Mikhail Vladimirov
  • 13,572
  • 1
  • 38
  • 40
0

Just a specific case correlated to the last question:

How do I ensure uniqueness if I want the user to be able to set the ID (or at least suggest IDs)?

If you want to do this, you have to keep track over all instances. You could use a BitSet for example. If you do this, you cold provide kind of a deconstructor:

/**
 * Eat the squirrel.<br>
 * You can not do anything anymore with the squirrel after it has been eaten,
 * but it can be reborn.
 */
public void eat() { //at least, sounds friendlier than kill, shoot, or whatever
  instances.clear(id);
}

Be careful, because this is not a real deconstructor like in c++. You can not (easily) destroy the object. It can still be used. You should take care of this internally then.

Hint: If you use multithreaded code, live starts to be complex. But apparently from the static id, you do not.

tb-
  • 1,240
  • 7
  • 10
0

I think to meet all of your requirements you will need a SquirrelFactory class to get new Ids and make sure they are all unique. You will probably want to make the SquirrelFactory a Singleton.

The responsiblities of the SquirrelFactory are:

  • Keeping track of ids in use
  • Creating squirrels with a new ID based on a counter ( and make sure it is unique )
  • Creating squirrels with given IDs (for when loading from a file) and if the id is already in use then creating a new like above
  • Adding the IDs of new squirrels to the list of IDs in use.
  • For testing you probably want a way to reset the counter and the list of IDs
  • (Optional) Have a way to remove ids from the list when the squirrel is removed
Stanley De Boer
  • 4,921
  • 1
  • 23
  • 31