开发者

How to test expiration conditions?

开发者 https://www.devze.com 2023-03-24 00:44 出处:网络
I\'m developing a component that provides tokens that have a limited lifespan and need not be 开发者_如何学Gopersisted in case of application restart. Hence, the tokens are only stored in memory. Each

I'm developing a component that provides tokens that have a limited lifespan and need not be 开发者_如何学Gopersisted in case of application restart. Hence, the tokens are only stored in memory. Each token is identified by a key and have an associated time-to-live after which the token expires and can no longer be used.

I halted to think how would you go about testing that the expiration conditions work as planned?

  1. The naïve implementation using System.currentTimeMillis does not provide a proper way to inject arbitary times to test the boundaries.
  2. Adding a datetime parameter (Calendar, Joda-Time's DateTime, etc) to the appropriate methods does not make sense outside of the testing context as it's not the responsibility of the caller to know what time it is.
  3. Wrapping the system time in a class that can be injected and mocked seems the way to go but feels a bit cumbersome. This would also require another constructor as a default implemention suffice in all but testing circumstances.
  4. Defining the lifespan as a setting would allow making the wait short enough to make a sleep() or a busy-wait a reasonable and reliable solution

I'm currently leaning towards option 4 but I'd learn about more options as well!

Overly simplified scribbled scenario:

private static final long LIFE_SPAN = 60000;
private Map<T, Long> bestBeforeDates = new HashMap<T, Long>();

public void add(final T key) {
   bestBeforeDates.put(key, System.currentTimeMillis() + LIFE_SPAN);
}

public boolean isExpired(final T key) {
  // How to make this fail without waiting for x milliseconds
  return bestBeforeDates.get(key) < System.currentTimeMillis();    
}


Option 3 is the best IMO. Getting the current time is a service like any other, IMO. It's easy to write a Clock interface and then fake it appropriately. If you're using a decent DI framework you don't need another constructor - just bind the a system implementation to the Clock interface and no further changes are required.

I've used this approach in a number of places and never regretted it. Of course, it depends whether you're already using dependency injection elsewhere - if it's the only dependency you'd be injecting, it's more of a pain.

0

精彩评论

暂无评论...
验证码 换一张
取 消