Search code examples
phpsymfonyfunctional-testingswiftmailer

Functional test for Email as Service in Symfony3


I am trying to write a functional test that checks Email is sent or not. My sendemail method is defined in service so I am not able to follow the example that is given in cookbook

Setup - Controller has a form, When form is submitted and valid it will call sendmail method in the service

Controller

public function sampleAction(Request $request){

   $sampleEntity = new SampleEntity();
   $form = $this->createForm(sampleType::class, $sampleEntity)
   $form->handleRequest($request);
   if ($form->isSubmitted() && $form->isValid()){
      ...
      $sampleservice = $this->get('sampleservice');
      $sampleservice->sendMail();

      return $this->render('sample/formsubmitted.html.twig');
   }
}

Service

public function sendMail(){

        $body = $this->renderTemplate();

        $message = \Swift_Message::newInstance()
            ->setSubject('Sample Mail')
            ->setFrom($this->sender_mail)
            ->setTo($this->admin_mail)
            ->setBody($body);

        $this->mailer->send($message);
    }

Test

public function testEmailSend(){

        $client = static::createClient();

        $client->enableProfiler();
        $crawler = $client->request('POST', '/sampleform');
        $client->followRedirects(false);

        $form = $crawler->selectButton('Submit Form')->form();

        $crawler = $client->submit($form);

        $mailCollector = $client->getProfile()->getCollector('swiftmailer');

        $this->assertEquals(1, $mailCollector->getMessageCount());

    }

Can this line be explained better $crawler = $client->request('POST', '/sampleform'); , in cookbook it says path to sendmail action but since it is not action in my case, what to write there or do I have to take whole new approach?

Apart from this I tried calling sendmail directly from service, assertEqual is giving me 0 since sendmail is not accessed(I guess). Any ideas on where and how to proceed. This is my first attempt to write functional tests so if I made some obvious mistake pardon me.

Edit 1

SampleType

public function buildForm(FormBuilderInterface $builder, array $options){

   $builder
            ->add('name', TextType::class, array('data' => 'Sample'))
            ->add('phone', TextType::class, array('data' => '1234567890'))
->add('save', SubmitType::class, array('label' => 'Submit Form'))
            ->getForm();    
}

Edit 2 When tried calling service directly, Is there any other way to call service directly ?

public function testEmailSend(){

        $client = static::createClient();
        $client->enableProfiler();
        $crawler = $client->request('POST', '/src/AppBundle/Service/SampleService/sendMail()');

        $mailCollector = $client->getProfile()->getCollector('swiftmailer');

        $this->assertEquals(1, $mailCollector->getMessageCount());

    }

This one returns "Failed asserting that 0 matches expected 1."

Mail gets send successfully in the Application, But want to make sure in test as well


Solution

  • From what I see in the cookbook entry, the enableProfiler only enables the profiler for the next request. Your submit is the second request. Enable the profiler before the form submit in your test.

    Also in your config_test.yml do you have profiler enabled: true and collect: true? See bottom of this page: How to Use the Profiler in a Functional Test

    Test

    public function testEmailSend(){
    
            $client = static::createClient();
    
            $crawler = $client->request('POST', '/sampleform');
            $client->followRedirects(false);
    
            $form = $crawler->selectButton('Submit Form')->form();
    
            $client->enableProfiler();
            $crawler = $client->submit($form);
    
            $mailCollector = $client->getProfile()->getCollector('swiftmailer');
    
            $this->assertEquals(1, $mailCollector->getMessageCount());
    
        }