如何在不睡觉的情况下对此协程进行单元测试

时间:2016-08-10 10:33:03

标签: python unit-testing python-3.5 python-asyncio

我正在尝试创建可以向现有协程添加以下功能的函数。

  • 根据参数将缓存添加到原始协同程序。
  • 添加ttl参数 默认为无穷大,以便调用者可以指定新鲜度 数据应该在它刷新之前。
  • 如果有人使用某些参数调用缓存的协程,而原始协同程序没有返回相同参数的结果,则第二个协程应该等待此结果并从缓存中获取结果。

我在测试最后一个条件时遇到了问题。

def cached(cache, locks, f):
    @wraps(f)
    async def wrapper(*args, ttl=float('inf')):
        value, updated_at = cache.get(args, (None, None))
        if value and updated_at >= time() - ttl:
            return value
        else:
            loading_sync = locks.setdefault(args, Sync())
            if loading_sync.flag:
                await loading_sync.condition.wait()
                return cache[args]
            else:
                with await loading_sync.condition:
                    loading_sync.flag = True
                    result = await f(*args)
                    cache[args] = result, time()
                    loading_sync.flag = False
                    loading_sync.condition.notify_all()
                    return result
    return wrapper

1 个答案:

答案 0 :(得分:2)

要对这种情况进行单元测试,您可以使用期货,您可以随意解决。在这里使用非常简化的@cached装饰器和函数:

@cached
async def test_mock(future):
    await asyncio.wait_for(future, None)

func1_future = asyncio.Future()
func1_coro = test_mock(func1_future)
func2_coro = test_mock(...)

func1_future.set_result(True)
await func1_coro
await func2_coro

原始答案,基于误解:

逻辑非常简单:你将缓存放在某个地方,让我们使用一个简单的字典。当您第一次遇到特定参数时,在缓存位置创建Future。每当您访问缓存时,请检查您的值是否为Future,如果是,await。非常简单的插图:

cache = dict()

async def memoizer(args):
    if args in cache:
        cached_value = cache[args]
        if isinstance(cached_value, asyncio.Future):
            cached_value = await asyncio.wait_for(cached_value, None)
        return cached_value
    else:
        future = asyncio.Future()
        cache[args] = future
        value = await compute_value(args)
        future.set_result(value)
        cache[args] = value
        return value