Testing In Golang, how to test cache that expires in 30 seconds

1.3k Views Asked by At

I have an interface called localcache:

package localcache

type Cache interface {
    Set(k string, v interface{})  error
    Get(k string) (interface{}, error)
}

and another file containing its implementation

type cache struct {
    pool map[string]value
}

type value struct {
    data      interface{}
    expiredAt time.Time
}

func New() *cache {
    if cacheInstance == nil {
        once.Do(func() {
            cacheInstance = &cache{
                pool: make(map[string]value),
            }
            go cacheInstance.spawnCacheChcker()
        })
        return cacheInstance
    }
    return cacheInstance
}

func (c *cache) Set(k string, v interface{}) (e error) {
    expiredAt := time.Now().Add(expiredIn)
    c.pool[k] = value{data: v, expiredAt: expiredAt}
    e = nil
    return
}

func (c *cache) Get(k string) (v interface{}, e error) {
    v = c.pool[k].data
    e = nil
    return
}

func (c *cache) spawnCacheChcker() {
    for {
        for k, v := range c.pool {
            if !(v.expiredAt.Before(time.Now())) {
                continue
            }
            c.evictCache(k)
        }
        time.Sleep(checkInBetween)
    }
}

a cache will be expired 30 seconds after it's been set, how can I test this functionality? I'm using testify rn, my brute force solution was to time.Sleep in the test function, but I feel like this will prolong the entire test process, which is not the best practice.

Is there any ways to mock the expiredAt inside the Set function? Or is there any workaround that tests this better?

1

There are 1 best solutions below

0
On

You can move time.Now() to be a field in cache struct like

type cache struct {
  nowFunc func() time.Time
}

then assign time.Now to it in the constructor. Within the test, just modify it to your mock function to return any time you want.