PolishSymfonyCommunity / Symfony2MockerExtension

Behat extension for mocking services defined Symfony2 dependency injection container
MIT License
27 stars 7 forks source link

Doesn't detect services method calls #2

Closed ouince closed 11 years ago

ouince commented 11 years ago

Hi,

I'm trying to mock Symfony2 services but it doesn't seem to work well.

Here is my controller:

   public function indexAction(Request $request) {
      $paymentManager = $this->get('payment_manager');
      $publishableKey = $paymentManager->getPublishableKey();
   }

In test mode, get_class($paymentManager) returns MyProject\DashboardBundle\Manager\PaymentManagerMock

Here is my context file:

   /**
    * @Then /^the payment manager creates a new customer$/
    */
   public function thePaymentManagerCreatesANewCustomer() {
      $this->mocker->mockService('payment_manager', 'MyProject\DashboardBundle\Manager\PaymentManagerMock')
              ->shouldReceive('getPublishableKey')
              ->once();
   }

Here is the exception I'm getting:

[Mockery\CountValidator\Exception]
Method getPublishableKey() from MyProject\DashboardBundle\Manager\PaymentManagerMock should be called
exactly 1 times but called 0 times.

Do you know what's happening?

Thank you!

jakzal commented 11 years ago

Could you also paste your feature and context files? At least the related parts.

Are you sure your controller is called?

ouince commented 11 years ago

Thank you very much for your reply. I hope I can make it work because I find this extension really useful!

Yes, I'm sure the controller is called, I've been working on this "bug" for few days now as I want it to work :)

Here is my features file (I've already paste the context one):

Feature: Register
  As a user
  I need to register

Scenario: Register
   Given I am on "/dashboard/register"
      And I fill the input "register[business][name]" with value "test"
      And I fill the input "register[business][emailAddress]" with value "test@gmail.com"
      And I fill the input "register[business][phoneNumber]" with value "123"
      And I fill the input "register[address][street]" with value "test"
      And I fill the input "register[address][city]" with value "test"
      And I fill the input "register[address][zipcode]" with value "123"
      And I fill the input "register[creditCard][number]" with value "123"
      And I fill the input "register[creditCard][cvc]" with value "123"
      And I fill the input "register[user][email]" with value "toto@gmail.com"
      And I fill the input "register[user][password]" with value "test"
   When I click on "submit"
   Then the payment manager creates a new customer
      And I should see "Welcome"

Actually, to be sure the code was executed, I've added a echo / die in the context function:

   /**
    * @Then /^the payment manager creates a new customer$/
    */
   public function thePaymentManagerCreatesANewCustomer() {
      echo 'test'; die;
      $this->mocker->mockService('payment_manager', 'MyProject\DashboardBundle\Manager\PaymentManagerMock')
              ->shouldReceive('getPublishableKey')
              ->once();
   }

Do you need something else?

Thank you!

jakzal commented 11 years ago

You mocked the service after it was called.

Mocking is a bit tricky, since with tools like Mockery (which is used in our case) you have to specify expectations before you exercise the code. That means you have to call your "the payment manager creates a new customer" step before clicking submit button. You'll probably want to rename your step to make more sense if called before performing an action.

You could also hide the call to mock your service in one of your other steps and add a step to verify expectations later (refer docs).

Be careful of what you're mocking. You should mock as little as possible with Behat since it should exercise all the layers of code. The only situations I see a point in mocking with Behat is when you're using an external service provider which doesn't offer you a test environment. In such case you wouldn't like to interact with the real service and it's better to mock.

ouince commented 11 years ago

Perfect, it works like a charm, you saved my day. Thank you!

You're right concerning mocking, but I want to make sure the calls to the service (which uses an external API) are made in my controller to avoid regressions later. Do you see a better way to do it?