gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
So if phpspec is all about helping you design your classes - helping you ask: how do I want this class to look and behave? - how... does it actually do that? The idea is cool: instead of jumping straight into your code and hacking until something works... or you get sleepy... stop... step back... and instead, first, describe how you want your class to behave.
We do that by creating a class called a... specification. That's a fancy... or maybe boring word that means that, before coding, we will first create a class where we simply describe how our future class will work and act.
Let's see this in action. Remember the two commands of the phpspec executable? The first is describe
- run it with -h
:
./vendor/bin/phpspec describe -h
I'm passing -h
to see the help details. Basically, each time you want to create a new class, you should first use this command to create a corresponding specification class. Oh, notice that forward slashes are used for the namespaces, that's just to avoid escaping problems.
Anyways, because we're building a dinosaur park, the first class we need is... Dinosaur
! So let's run:
./vendor/bin/phpspec describe App/Entity/Dinosaur
I could have chosen any namespace starting with App
- that's up to how you want to organize your code. But, if you're used to Doctrine in Symfony, this will feel familiar.
Ok! One new file: DinosaurSpec.php
. Let's go check it out! Ok - so phpspec
creates a spec/
directory, which is meant to have the same file structure that our classes will eventually have in src/
.
Open the new file. Ok... these spec classes look a little weird at first - and we're going to talk a lot about them. The purpose of this class is for us to describe the behavior of our future Dinosaur
class. On a philosophical level, we do this by writing example code: using our Dinosaur
class as if it already existed and was finished.
... lines 1 - 8 | |
class DinosaurSpec extends ObjectBehavior | |
{ | |
function it_is_initializable() | |
{ | |
$this->shouldHaveType(Dinosaur::class); | |
} | |
} |
On a more concrete level: we describe the behavior through examples. Every function in this class that starts with it_
or its_
will be read by phpspec as an "example". They are the key to phpspec, and also the most complex part.
There are two very important things to understand about the code inside these example methods. First, and this is truly magic, you're supposed to use the $this
variable as if we were inside of the Dinosaur
class itself. Literally: you treat $this
like a Dinosaur
object - showing examples of how you want it to work by calling methods on that class - like $this->getLength()
if the Dinosaur
class had a getLength()
method.
In addition to using $this
to call methods that exist - or should exist - inside Dinosaur
, the second important thing to know is that you can also call a huge number of methods that start with should
or shouldNot
. These are called "matchers" - and they are the way you assert that things are working correctly in phpspec.
In the one generated example function, because we're pretending to be inside the Dinosaur
class, we pretend that $this
is a Dinosaur
object. When we call ->shouldHaveType(Dinosaur::class)
, this asserts that the object is an instance of that class... which, by the way, doesn't even exist yet! It's a pretty pointless test - but I usually keep it.
Oh, and the last strange thing about this class is that... it violates coding standards! Did you notice the missing public
before the functions? That's totally legal in php - methods are public by default. And the method names are written using snake-case instead of camel case. Both of these things are done on purpose for one important reason: readability. We're writing PHP - but this class is meant to be a human-readable description of our future Dinosaur
class. And right now, our specification says nothing more than a Dinosaur
object should be... a Dinosaur
object.
Ready to execute the other phpspec command? It's called run - let's show the help details on this one too:
./vendor/bin/phpspec run -h
This is the main command in phpspec. Its job is to look at all of our spec files - just one right now - and all of the example methods inside - and verify whether or not the actual class behaves like we've described with that example code.
Now... you might think that's a bit crazy. After all, how can phpspec look to see if our Dinosaur
class has the correct "behavior"? The Dinosaur
class doesn't even exist yet! Heck, there's nothing in our src/
directory at all! Well... let's see what happens:
./vendor/bin/phpspec run
At first, it does fail because App\Entity\Dinosaur
does not exist. That's expected. But check this out: it's asking: do you want me to create it for you? This is what makes phpspec
so fun! When it sees that you've described some behavior that's missing, it can create it for you! Let's choose yes, of course!
... lines 1 - 4 | |
class Dinosaur | |
{ | |
} |
Cool! Go look - in src/
... there it is! It doesn't do anything, but... actually... our new class now has the behavior described in our spec. To prove it, re-run phpspec:
./vendor/bin/phpspec run
Woh! It works! That... does make sense. Even though we don't understand much about how the "examples" work yet, after generating the code, if you try to create an instance of a Dinosaur
class..... you do get a Dinosaur
object! Eureka!
Next: let's start creating some meaningful examples of how our class should behave and see how phpspec can help us build that.
Hey Emakina F.!
Ah! I don't like that error at all! Do you have a connection()
method anywhere in your code? I thought at first that this error might be some low-level error coming from phpspec. But, if I search the entire vendor/ directory of this project, I don't see any method called "connection()". So I'm wondering if this might be referring to something in your code?
Cheers!
Thanks weaverryan for response.
I don't have that method in my code and I don't have any idea about that. When I started with pure PHP & PHPSpec it works well, but when I tried to use PHPSpec on Slim Framework entities it failed. I thought it might be Slim related.
Hey Emakina F. !
Hmm. Indeed. Doing some quick googling, it looks like it could be from Eloquent - are you using Eloquent with Slim by chance? I don't know the fix exactly, but if you search for "Call to a member function connection() on null slim" or "Call to a member function connection() on null eloquent" you'll see references. What's odd is that everything is mocked in PHPSpec... so it "shouldn't" (with big quotes) matter what ORM or framework you're using. But... it seems something is going on here related (I think) to Eloquent.
Cheers!
Hi weaverryan
Yes, I am using Eloquent with Slim in that application, thanks a lot for better googling then me :D I will take care of it, have a nice day :)
Hi!
I have problem when I running command, on my win10
php vendor/bin/phpspec describe -h
Output is:
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../phpspec/phpspec/bin" && pwd)
if [ -d /proc/cygdrive ] && [[ $(which php) == $(readlink -n /proc/cygdrive)/* ]]; then
# We are in Cgywin using Windows php, so the path must be translated
dir=$(cygpath -m "$dir");
fi
"${dir}/phpspec" "$@"
How can I resolve this problem?
Thank you!
Maybe i can offer a solution that is a bit more... well "handy". In my case this is a symfony-project.
Go to your Project-Root and find the "bin" folder. Make a new file named phpspec and paste this chunk of code right in:
`#!/usr/bin/env php
< ? php // <-- please note, that i had to fill in whitespaces here, because disqus doesen't like my post otherwise
if (!file_exists(dirname(DIR).'/vendor/phpspec/phpspec/bin/phpspec')) {
echo "Unable to find the `phpspec` script in `vendor/phpspec/phpspec/bin/`.\n";
exit(1);
}
require dirname(DIR).'/vendor/phpspec/phpspec/bin/phpspec';`
Now you should be able to call phpspec simply by typing the command "php bin/phpspec run".
Aaaand it feels more "natural" if you work with "php bin/console" and "php bin/phpunit" too :D
Maybe this makes things more beautiful =)
Ok, I have already resolved the problem. Instead of using
php vendor/bin/phpspec describe -h
I use:
php vendor/phpspec/phpspec/bin/phpspec
Hey MichalWilczynski!
Yes! Nice find! OR, use try this syntax:
./vendor/bin/phpspec
(or you may need to change the slashes \.vendor\bin\phpspec
). The phpspec is a "bat" file for Window, so instead of executing it via php, you're supposed to execute it directly. But, it's just kinda tricky. You'll notice that in the script we always use the ./vendor/bin/phpspec
version of the command - it's a bit more portable across operating systems.
Cheers!
Great!
Your solution also works! I changed slashes to backslahses and command
.\.vendor\bin\phpspec
works like a harm :D
Hey Nicoweb!
Why do you think so? :) We're working on phpspec tutorial right now, that's why it's been releasing these days. The previous one: "Symfony 4 Forms: Build, Render & Conquer!" - was completely released recently :)
P.S. But sure, releasing a few tutorials at the same time is our goal :)
Cheers!
Hi!
When I run the test, phpspec throws an error instead of suggesting me to create the non-exists method on real class.
// my test method
function it_shoult_return_5()
{
$this->getLength()->shouldBe(5);
}
// error
App/Models/Student
16 - it shoult return 5
exception [err:Error("Call to a member function connection() on null")] has been thrown.