Transcript
00:00 To create a good fake, I would first have to understand how the thing I'm faking works. In this case, it's the FileStorage class. So let's take a look. This class has two methods, setItem and getItem. And they're responsible for uploading and retrieving files from the server, respectively. But of course, I don't want the server to be the place where the files are stored when
00:19 I'm testing. Instead, it would be much better if we stored those files in memory. And to do that, in my fake FileStorage, I will create that place. I will create a private variable called data, and I will assign it to a new map. This will be my in-memory key value storage, where keys would be file names and values
00:38 would be arrays of file chunks, the buffer. Then I will implement the setItem method, and I will be type-compliant because I'm using the implement keyword, so it forces my fake implementation to have the same types, so call signatures and return types, as the original class.
00:55 And here I will store this file in memory by key and value, and also return an empty promise because this method is asynchronous, but we are not doing anything asynchronous in this fake. And then of course, I will implement the getItem method in the same fashion, but I will return
01:13 an empty promise that resolves to the lookup of this file from memory. So this concludes a very simple fake FileStorage. Now let's use it in tests. So in this scenario, we're uploading a small file.
01:26 Let's create a store that will be an instance of our fake FileStorage, and I will provide that storage as an argument here to the upload service. Here our service is configured to have five bytes as the maximum chunk size for a file,
01:44 and we're uploading a file with content hello, which is exactly five bytes, so we will expect a single chunk to be uploaded saying hello. So the result of calling upload will be this uploaded entry in the storage. For convenience, I will map it to string using buffer from, so the diff would be much nicer
02:02 in tests when something goes wrong. And finally, I will write this assertion, I expect chunks to be a single chunk that says hello. What about larger files? So in the second test case, I will create the same storage instance and provide it to the upload service.
02:17 It's the same setup and the same max chunk size limitation, but here we're uploading a file hello-world, which is quite more bytes. So we have hello, first five bytes, then dash world, another five, and finally D as the last chunk. So here we're expecting to have three chunks uploaded to the storage.
02:37 So the same convenience to cast chunks to strings and expect chunks to have three entries hello-world and D. Now let's verify this by running the test. So NPM test. Okay, I see something failing. Oh yeah, I included world.
02:57 Yes, just the first five bytes. So now I can confirm that both small and large files are uploaded correctly. So here we're using what is called a fake. Unlike mocks, fakes are often stateful and they actually exhibit some behaviors.
03:13 So why wouldn't we just mock this file storage module or maybe mock and spy on the storage methods? So if we spied on something like get item and set item, we would have to pretend that we have state because we provide just exact literal values.
03:29 So instead, we're introducing this fake that actually keeps uploaded files in memory. So we're able to have the complete data flow from the upload service to storage and back. So we are asserting on the actual file chunks that are being uploaded.