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

huangapple go评论92阅读模式
英文:

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

问题

我有一个名为localcache的接口:

package localcache

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

还有另一个文件包含了它的实现:

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)
	}
}

缓存将在设置后的30秒后过期,我该如何测试这个功能?我现在正在使用testify,我目前的解决方案是在测试函数中使用time.Sleep,但我觉得这会延长整个测试过程,这不是最佳实践。

有没有办法在Set函数内部模拟expiredAt?或者有没有其他更好的测试方法?

英文:

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

得分: 3

你可以将time.Now()移动到缓存结构体中作为一个字段,例如:

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

然后在构造函数中将time.Now赋值给它。在测试中,只需将其修改为你的模拟函数,以返回你想要的任何时间。

英文:

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.

huangapple
  • 本文由 发表于 2022年3月26日 13:05:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/71625462.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定