Transcript
00:00 Before we dive into mocking modules, let's first explore some alternatives to it. One of such alternatives is dependency injection and using fakes. But what is a dependency injection? Well, dependency injection is a software design technique that helps you reverse the relationship between your dependencies. Let me give you an example.
00:20 Here we have an upload service that basically is responsible for uploading files. To provision the actual uploads and file retrieval, it depends on the file storage. And it constructs an instance of that file storage in its constructor and stores it in a variable called storage, this.storage. So then it uses it during the upload phase.
00:40 So basically, upload service depends on the file storage. But the nature of this dependency is implicit. In fact, if you're consuming the upload service class, you don't even know that it creates the storage instance internally. So if you would want to exclude the behaviors of the file storage when testing your upload service,
00:58 you would have to leak the fact of this dependency into your test. And that's not nice because it results in brittle tests. Now, if you decide to refactor things, refactor this relationship between classes, or maybe change class behaviors, your test may also fail. So how can we change this dependency?
01:17 Well, what if we accept the storage as an argument to this constructor? So storage is file storage. And basically, so what we did, we're now accepting the storage instance as an argument to upload service. What we did here is effectively lifted this dependency up.
01:36 So now the consumer decides which file storage to use with particular upload service. And this is really handy because we can provide any file storage instance, including a fake one. And you're going to utilize this greatly to great effect in your tests. But before you do that, let me talk about the dangers of dependency injection. As I mentioned before,
01:57 dependency injection is a software design technique. It's not a testing technique. In fact, I'm a huge opponent of refactoring your code just so it would be easier to test for you. Because you're not writing your software for yourself. You're writing it for the end user, whether it's an actual consumer of your product or another developer.
02:15 So you need to make sure that the API decisions you're making have their best interests in mind. What this means is that you shouldn't go and just refactor everything you have to use dependency injection. That would likely be a bad decision. But instead, if you already see the code that utilizes this pattern, you need to leverage it when testing.
02:35 And this brings me to your task in this exercise. You will be testing this actual upload service class, which is very similar to the example I've just shown you. It has an upload method and uploads any given file. The logic of this upload service itself is to split large files into chunks using this maximum chunk size as the splitting point.
02:55 And then it delegates the upload of the file to the storage instance that it also accepts as an argument. So it already uses dependency injection. In this test, you will be testing the upload functionality both for small files and larger files. And you will do so by creating a fake storage, fake file storage.
03:13 It will be an actual class that implements the real file storage. But instead of relying on the HTTP protocol to do the uploads, you will store the files in memory. And of course, by the end of it, you should have the test passing by running NPM test.