使用 s3fs(通过 dask)测试模拟 S3 存储桶的行为是意外的

Testing behavior of a mocked S3 bucket using s3fs (by dask) is unexpected

我有一个简单的功能,可以将文件添加到基本 S3 位置。基本位置作为环境变量给出:

os.environ["TEST_BASE"] = "my-bucket/testing/"

函数是:

def add_file(file):
    print(f"In function: {os.getenv('TEST_BASE')}")
    s3 = s3fs.S3FileSystem()
    s3.touch(os.getenv('TEST_BASE') + file)
    print("In function: " + str(s3.ls(os.getenv('TEST_BASE'))))

现在,我想测试它的行为:

with mock_s3():
    with unittest.mock.patch.dict(os.environ, {"TEST_BASE": "foo/bar/"}):
        print(f"TEST_BASE = {os.getenv('TEST_BASE')}")

        s3_conn = boto3.client('s3', 'us-west-2')
        s3_conn.create_bucket(Bucket='foo')
        s3 = s3fs.S3FileSystem()
        s3.touch(os.getenv('TEST_BASE') + 'yoo')
        print(s3.ls(os.getenv("TEST_BASE")))
        add_file('goo')
        print(s3.exists(os.getenv("TEST_BASE") + 'goo'))  # (*)
        print(s3.ls(os.getenv("TEST_BASE")))  # (**)
print(f"TEST_BASE = {os.getenv('TEST_BASE')}")

现在,我无法理解的部分是 (*) 打印 True 但是 (**) 仅列出一个对象(yoo).这是怎么回事?

可能发生的情况是 mock_s3 函数中的 s3 对象出于性能原因正在缓存目录列表。您使用单独的实例创建新的空文件,因此外部实例不知道任何内容已更改。尝试在 add_files3.ls 之间插入 s3.invalidate_cache()

unittesting 的上下文中,我得到了以下 setUpteadDown

def setUp(self):
        self.mock_s3.start()
        s3_conn = boto3.client('s3', 'us-west-2')
        s3_conn.create_bucket(Bucket='bucket')
        self.s3 = s3fs.S3FileSystem()

def tearDown(self):
    self.mock_s3.stop()

并避免了装饰器的使用。这对问题中描述的案例没有直接帮助,但是,由于这个用例对我来说是个问题,所以我把它放在这里以供参考。