[16/38] - Using PhpSpec to Test our FileMover
6K views
Feb 14, 2023
Code and write up - https://codereviewvideos.com/course/let-s-build-a-wallpaper-website-in-symfony-3/video/using-phpspec-to-test-our-filemover We have all the pieces in place to start writing code that we can test using PhpSpec. Now we're going to create our tested FileMover service.
View Video Transcript
0:00
Hi, I'm Chris from CodereviewVidio.com and in this video we're continuing our file mover
0:08
test and implementation. Now going back to our implementation, to actually be able to move a file, we can do this in a multitude
0:16
of ways. The three that I can think of off the top of the head are to use either PHP's built-in functions
0:21
or we can use something like Fly System or Gau-Ret, some sort of file system abstraction, or
0:26
we can use the Symphony File System component. Well, as we're using symphony anyway, we might as well make use of the components it provides
0:33
We've already got them. We don't need to include any other dependencies. And as this is a symphony service, the way in which we'll get access to that file system is to simply inject it
0:42
Now, if you're unsure, what we can do at this point is do a PHP bin console, debug, container
0:48
and then we'll pass in file system as the thing that we're looking for. And you can see here it dumps out all the service information for us
0:54
The one that we're interested in here will be the service ID, which is file system
0:58
or one word lowercase and because we're going to be injecting this
1:02
we'll need to prefix it with the at symbol to indicate that it's a service
1:06
But knowing this, if we're going to inject it, we can go ahead, set this up
1:10
via a constructor to inject our concrete implementation of the symphony file system
1:15
And notice the use statement's been brought in. I'm going to alt and return on that on a Mac
1:19
to initialize the fields. That should all be good And then I going to add the implementation here So it this file system and then there a bunch of methods that you can do with it The one we interested in is rename We going to rename from the existing file path to the new file path And unfortunately
1:35
this is actually a void method. If we look at it, it doesn't return anything. It throws a couple
1:39
of things and that's quite useful, but it doesn't actually return anything, which is why we can't
1:43
just simply return the outcome of this. That's why we have to return true. So now if we try and run
1:48
our tests again, you can see that both of them have broken. This is to be expected because now
1:54
we've just changed the implementation to expect that we're passing in a file system instance
1:58
but inside our spec, we're not really doing that at all. So we can start fixing this by injecting
2:04
a file system into each test, making sure that we've got the right use statement, and I'll just
2:09
call that FS just to make it a little bit more shorthand, and again we can do it for this one
2:13
and then what we can do, apologies, what we can do is do this, be constructed with
2:18
and I can say FS to make sure that whenever we call our file mover
2:23
it gets constructed with an instance of the file system. So again, we'll run our test now and we're back to passing
2:28
because we're injecting the expected dependency. But of course, you don't want to keep having to do this
2:33
for every single test that you create. So PHP spec's got a better solution to this
2:37
which is the let function. So we'll just say let, create that
2:41
and we'll say be constructed with. That's cool, and that's cool. We don't need these anymore
2:46
So just get rid of them but I do need it inside the let method or the let function So now we should still have two passing tests which we do albeit with a little less duplication
2:56
Okay, but let's look back at what our tests are actually testing. So we've got, it is initializable, and that checks that this file mover class exists
3:04
And also now, in our case, that our constructor depends on a file system
3:08
But it's not really testing anything in terms of our implementation. For that, we've added our own test
3:13
It can move a file from temporary to controlled storage, and we call move. with our current location or new location, it should return true
3:19
And that test is passing. We're not actually testing anything to do with this injected file system
3:25
So this isn't actually an instance of the file system. It's called a collaborator
3:29
And we can see this if we cheat a little bit, and we'll do a dump here
3:34
And just rerun our test now, and you can see that what's been dumped out is an object that's an instance of a PHP spec collaborator
3:41
And effectively what this allows us to do is completely fake out the dependencies
3:45
but also spy on them, by which I mean that we can check now that inside our file mover
3:50
this file system renamed was called with these two expected arguments. So let's do that
3:56
So we've got let file system. What we're going to need to do is get access to this file system a little later on in our test
4:02
And to do that, all we need to do is say this file system or whatever property you wish to create
4:08
It equals FS. And then we'll just add that as a private field
4:12
Okay so we constructed with it and everything and then we go into our test and after our test is run what we could now do is say this file system rename with these two properties or two arguments
4:24
should I say should have been called so we expect this file system rename with that and that to
4:30
have been called and if so then we should have a passing test that's quite cool and what it means is
4:36
if we jump inside our file mover maybe we change this out to be just one two three just to break it
4:41
run our tests you can see that we didn't quite meet the requirements of our tests
4:46
So we know, even though we're not testing the symphony component, which has its own unit tests and is completely isolated from us
4:52
we know that if we send in the right arguments, assuming that code all works that symphony are providing
4:57
and that's a fair assumption to make, then our code should behave in line with that
5:02
So that's really useful, in my opinion. And again, just to bring that out, rerun the tests, and we're all good
5:07
So really the only thing that's left to do at this point is to make sure that we have the appropriate service definition set up
5:13
So this is really straightforward. We're going to have app, service, file mover
5:18
It's going to have the class of app, bundle, service, file mover
5:22
And we know now that it takes one argument, which is the app file system
5:26
So let's just take a quick copy of that. Do a PHP bin, console, debug container
5:32
Paste that in and you can see, well, it didn't throw an error so we can be pretty certain that this service is properly configured