-
Notifications
You must be signed in to change notification settings - Fork 7
[WIP] common collaborators #3
base: master
Are you sure you want to change the base?
[WIP] common collaborators #3
Conversation
@@ -0,0 +1,2 @@ | |||
extensions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for the example. (to be removed)
I was actually planning to register common service by default. I also don't like the fact we need to call However, I wouldn't limit the registration of collaborators to the common ones. It would be nice to have them by default, but it would also be nice to be able to add more of them in an easy way (without the need of putting them to the container "manually"). It would also make it easier to implement automatic registration of new services in a DIC config file. As for the extended container - I think it's no longer needed (there were issues with earler phpspec versions, i have to check that again). One proposition: I found it really useful to describe features in Gherkin (initially in the issue description on github). Can we make an experiment and try working on new stuff in this way? It's easier to understand what needs to be implemented and more people could pick up the tasks. I won't be able to give it some more thought before Symfony Live :( |
yeah sure! I wanted to create scenarios with this. I will write some gherkin to describe the poposed behavior. |
Would you like me to continue on this feature? Also, concerning your point about a config file that describes what are common collaborators (right?), It's just empty atm. |
@@ -0,0 +1,7 @@ | |||
extensions: | |||
PhpSpec\Symfony2Extension\Extension: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this using the new options parameters PR from phpspec/phpspec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reverted it until (if) the PR is (not) accepted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was breaking travis, cause composer was not using the PR'd version.
@@ -22,7 +22,7 @@ public function createWorkDir() | |||
// paths between scenarios. | |||
$this->workDir = sys_get_temp_dir().'/PhpSpecSymfony2Extension/'; | |||
|
|||
mkdir($this->workDir, 0777, true); | |||
@mkdir($this->workDir, 0777, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🐴
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what with that ? 🐫
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👶 maybe he means the @ handling
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah :) it's acceptable in that case imho
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
si un médecin le dit, nous buvons 👶
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha :) don't trust me.
ping @jakzal |
@docteurklein I'm looking into it and soon will express my opinion :) We have to be really careful on what we decide now. PhpSpec encourages to use good coding practices and makes writing bad code painful. We should follow the same values :) |
First of all, great work @docteurklein! I'm sorry I didn't come back to you earlier. I'm a bit concerned that with this PR we're making too many things implicit. Reading a spec no longer tells us the whole story, since the way collaborators are created would be hidden. The value of specing controllers is that we're being forced to make them simple. As soon as we get to mock too many collaborators, or handle too many execution paths, we're starting to think whether there's a concept missing. That's when we start thinking of yet another collaborator which could hide interactions with the others (for example). Implicit mocking would encourage bad practice I'm afraid. At least it wouldn't discourage it. I think It should be at least visible in the spec with what kind of services we intend to work with. I'm definitely voting 👎 against defining collaborators in the config file (as the config file is centralised). I know I should proposed another way, but I didn't think this part through yet. As for the use of We could replace the whole container injector thingy with a generated spec, which would contain code we intend to write most of the time: class UserControllerSpec extends ObjectBehavior
{
function let(ContainerInterface $container)
{
$this->setContainer($container);
}
function it_is_container_aware()
{
$this->shouldHaveType('Symfony\Component\DependencyInjection\ContainerAwareInterface');
}
} I count on a good discussion before we decide. The decisions we'll make now are very important as they'd be hard to roll back. |
Hey! Very happy to read your opinion :) I totally agree on the fact we shouldn't facilitate bad practices. I also agree on the problem of separating some parts in the yaml config and the other in the spec class, making the latter not anymore self-contained. I didn't really think of these 2 points, at the time I wrote this :/ My goal was to avoid long boilerplate code for controller specs. But as you said, if we start to write loooong let methods, we're doing it wrong, and we should feel some pain, Still, I see some advantages of predefinied mocks. For example, doctrine. |
Same thing for So, do you agree on the fact we should have preconfigured mocks at least ? (whatever the method.) |
I'd like to add my thoughts on this PR :) First thing - totally agree that mocking Request every single time is painful and having it preconfigured is a good thing 👍 According to discussion that we had with @richardmiller and @jakzal I think we should avoid injecting instance of container to our controllers and instead inject only services that are needed and define controller as a service itself. Because injecting container was introduced to ease Symfony learning curve I think it is useful on the beginning, but then people are bit stuck with this idea. My point is to encourage people to make dependencies explicit and force them to create thin controllers which leads to create services that do only stuff we need in this particular case and inject them to the controller. I understand that some peopled don's see that much value in this approach but I think somehow forcing it would be beneficial. The other thing is there is no one "right way" of writing controllers ;) And closing this extension to only one solution is not the best thing. As @everzet said we should think about some extension points to allow people make use of their workflow (if they have it :) ). |
I don't think this extension should set out to facilitate a practice which is ostensibly poor, and potentially in a way that makes the tests a little less obvious. Anecdotally having just refactored a non-trivial codebase to use phpspec/prophecy, if the container had been used a lot less as a service locator (mainly in controllers) my job would have been a lot easier. I think this extension should facilitate working with Symfony where the user has less of an option, for example as has already been mentioned mocking/stubbing the |
I have to agree with @peterjmit. It seems to me the issue is in the difficulty in making controllers as services (it has its own dedicated web page; http://symfony.com/doc/current/cookbook/controller/service.html), not in testing controllers that are already controllers that have properly defined dependancies. Perhaps a specific set of Symfony2 description generators are a better location to target for this? Something that would simplify the workflow of just making a controller as a service. How about:
This could build a controller named MyController inside of AcmeBundle, and generate the boilerplate (yml/xml/etc) to pass in the template dependency as well as allow the typecast to be set. (After typing that out, I realize I don't exactly like my syntax structure of my proposed command, but I don't have a more elegant concept yet). Also, I am linking @peterjmit's blog here, as this has a much better feel for how to accomplish the goal to me. |
Just to be clear: this PR doesn't encourage bad practices, it only preconfigures a mock if you use it. @awildeep concerning generators: I don't think it's the role of phpspec to build all this (yml, ...). To generate the class/methods is enough. This PR is more generalistic, as it focuses on every class (currently only I think we should discuss about how useful it is to have preconfigured mocks. |
@docteurklein Request is an extreme example where having preconfigured stubs would be very useful. It might even be worth considering if this feature should be part of the core. Anyways, I think the problem of this particular request is that it also relates to the container. My proposition is to take care of these two problems separately. |
@awildeep The issue most people have when they start using a service as controller is that they don't update their routing to reference the service id instead of the class name, and so the controller resolver does not use their service (it will not magically guess that you have a service defined with this class and it should use it instead of the normal instantiation logic). And the routing for controllers as services is documented. But I suspect people will read only half of the doc only before trying |
@stof It seems to me that is just a matter of making doc more readily available, and perhaps making the tooling easier to use. After all people will choose the path of least resistance most of the time until they have a specific need to do otherwise (I have fallen into this category before for sure). But as I have a goal of easily testable code, Symfony2 Controllers (non-service based) really fight against me. I am not sure if this particular discussion belongs here; perhaps it belongs as a Symfony2 discussion as a whole. |
}); | ||
|
||
$container->setShared('collaborator.initializer.templating', function ($c) { | ||
return new Initializer\Router; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops Templating
I have in mind to decouple "common collaborators" management from symfony2 extension. |
I'm currently implementing a Maintainer for ContainerAware objects that creates preconfigured collaborators.
For example, in a spec:
As you can see, the container is preconfigured to return a
RouterInterface
instance for$this->container->get('router')
call.Same for common services like
request
,session
, ...This would superseed the ContainerInjecterMaintainer + the ContainerInitailizerMaintainer.
I also consider the method I describe a bit cleaner, for the following points:
pros
ControllerBehavior extends ObjectBehavior
$this->container
property in the spec. (if we start to do that, we'll soon have dozen of spec properties)cons (if any):
Adding your own common collaborators
There is already an entry point to add your own, which is to add a key into the
symfony2.common-collaborators
param.This array supports 3 different syntaxes:
name: {containerIdName: FQCN }
name: FQCN
name: ~
In the last case (null), the className configuration is delegated to initializers (f.e: request ).
You can also register an initializer that will add more behavior to
$verySpecialCollaborator
.Just implement the
supports($name)
method (and others) and register a service with prefixcollaborator.initializer
.PS: the maintainer will apply only if CUS (class under spec) implements ContainerAwareInterface. That's maybe a problem.
I'd be curious to have your opinions on this @everzet @jakzal @MarcelloDuarte .