Getting laravel & phpunit to send message when unit test fails - unit-testing

I am using a function that tests for existence of an array in each page. I am using laravel's function assertViewHas. This would be fine if I had a function for each page testing for this array existence, however it seems waste of time, when I could just have a foreach running the test for each page. However, if one of the page's fails the assertion, I won't know which it is, phpunit will just say the test has failed.
So, is there any way of writing the current $page in the fail error when running phpunit in the command line?
....private $guest_pages=array('/','login','signup');
....
public function testGuestViewsHaveContent ()
{
foreach ($this->guest_pages as $page) {
$response = $this->call('GET', $page);
$this->assertViewHas('content');
}
}

Have you tried echoing $_SERVER['SCRIPT_NAME'] ?
Edit:
Duh... OK this does not answer your question, I didn't understand at first.
So, assertViewHas comes from Laravel's extending PHPUnit
vendor\laravel\Illuminate\Foundation\Testing\TestCase.php and basically checks if it's a view instance, if it's an array and just $this->assertEquals for each value.
assertEquals can have a custom message as a third parameter, so what you can do is modify your test, not using assertViewhas but assertEquals in a similar way as in assertViewHas (extending PHPUnit, not Laravel's testcase) and provide your custom message.

Related

How to check number of emails sent by Symfony in Codeception unit test

I can test for the number of emails sent in a functional test, but I haven't been able to test for the number of emails sent in a unit test.
I'm testing a Command that sends different numbers of emails depending on the test setup.
When I use:
// tests
public function testShouldSendATestEmailWhenNoParametersArePassedIn() {
$this->assertSame('Success! (Provisionally, as long as no errors follow.)' . PHP_EOL, static::run_verify_send_email_command());
$this->tester->seeEmailIsSent(3);
}
I get the following error:
[TypeError] Argument 1 passed to Symfony\Component\HttpKernel\Profiler\Profiler::loadProfileFromResponse() must be an instance of Symfony\Component\HttpFoundation\Response, null given
If I comment out $this->tester->seeEmailIsSent(3); the test runs and covers the appropriate code.
The Profiler seems to only be a functional test thing (i.e. using HTTP, not the command line), not a unit test thing. How can I test for the number of emails sent by a Symfony Command in a unit test?
I looked at the code again and realized that upgrading codeception/module-symfony won't help. seeEmailIsSent only works if simulated HTTP request was made by test.
Correct approach in unit test is to inject a mock of mailer class to the class or function that you are testing.
public function testEmailIsSent()
{
$mailerMock = $this->createMock(\Symfony\Component\Mailer::class);
$mailerMock->expect($this->once())->method('send');
$testInstance = new MyClass($mailerMock);
$testInstance->toSomething();
}
Read more information about mocks at https://phpunit.readthedocs.io/en/9.5/test-doubles.html

Mockito, TooManyActualInvocations when testing conditions Spek Framework

For a scenario unit testing a user entering a password and password confirmation. when i try to verify the same method being called in a different on() block, i get the following error on the 2nd on()block.
org.mockito.exceptions.verification.TooManyActualInvocations:
activationPasswordView.disableButton();
Wanted 1 time:
But was twice
Here is the code:
given("user set password "){
on(“password is null”){
presenterImpl.validatePassword(null, null)
it("done button should be disabled"){
verify(view).disableButton()
}
}
on("input only one password"){
presenterImpl.validatePassword("Password", "")
it("done button should be disabled"){
verify(view).disableButton()
}
}
}
But if i call a different method, it works correctly. I assume this was not how Spek framework was intended to be used as all the examples i have seen always use an Assert. Is there a way i can write the following conditions in Spek without the error?. Even a different given() still causes the error.
The mocked object counts the number of times the function invoked for the specific mock.
Since you did not reset the mock between each test, the counter is increased each time you invoked the method.
You should use: reset(view) to reset the mocks counter.
This issue is not related to the Spek framework.

Unit testing Promise task in grails

How do we unit test logic in Promises.task?
task{service.method()}
I want to validate invocation of the service method inside the task.
Is this possible? If yes, how?
I read in the documentation that in unit testing async processes, one can use this:
Promises.promiseFactory = new SynchronousPromiseFactory()
Tried adding it in my setup, but still does not work.
The long way
I've been struggling with this for a moment too.
I tried those:
grails unit test + Thread
Verify Spock mock with specified timeout
Also tried the same solution from the docs as you:
Promises.promiseFactory = new SynchronousPromiseFactory()
All went with no luck.
The solution
So I ended up with meta classing.
In the test's setup method, I mocked the Promise.task closure, so it runs the closure in the current thread, not in a new one:
def setup() {
Promises.metaClass.static.task = { Closure c -> c() }
// ...more stuff if needed...
}
Thanks to that, I can test the code as it wouldn't use multi threading.
Even I'm far from being 100% happy with this, I couldn't get anything better so far.
In recent versions of Grails (3.2.3 for instance), there is no need to mock, metaClass or use a Promise factory. I found out the promises in unit tests get executed synchronously. Found no doc for that, I empirically added a sleep inside a promise and noticed the test waited for the pause to complete.
For integration tests and functional tests, that's another story: you have to change the promise provider, for instance in BootStrap.groovy:
if (Environment.current == Environment.TEST) {
Promises.promiseFactory = new SynchronousPromiseFactory()
}
Like Marcin suggested, the metaClass option is not satisfactory. Also bear in mind that previous (or future) versions of Grails are likely to work differently.
If you are stuck with Grails 2 like dinosaurs such as me, then you can just copy the classes SynchronousPromiseFactory and SynchronousPromise from Grails 3 to your project and then the following works:
Promises.promiseFactory = new Grails3SynchronousPromiseFactory()
(Class names are prefixed with Grails3 to make the hack more obvious)
I'd simply mock/override the Promises.task method to invoke the provided closure directly.

Unit testing a controller that invokes a method that checks the DOM for a property

I am writing a unit test for a controller where somewhere in the workflow checks the DOM for a specific property. Currently I am just mocking the method via
spyOn(controller, 'methodChecksDom').return('value that I want').
Works fine but how do I make the test pass without mocking that method. I've tried using $document and actually inserting dom via
$document.find('body').append('<div>...</div>')
but I get the following error in my test:
Error: Dirty test! DOM residue found in document body: ...
at Error (native)
What is the proper way of doing this. Testing the method without mocking it. Many Thanks!
If you're dead set on testing the DOM directly here, you need to clean up the inserted element after the test. That's why you're getting an error--you're not cleaning up the thing you inserted via $document.
That being said, you really should not be even so much as reading the DOM inside of a controller.
You should do any DOM manipulation or adding of behaviors by using a custom directive.
http://docs.angularjs.org/guide/directive
angular.module("myApp",[]).directive("mydirective",function(){
return {
link: function(scope,iElem,iAttrs) {
//Do stuff per instance here
}
}
})

How do I Unit Test the Output of a View in MonoRail?

I've been trying to write some initial NUnit unit tests for MonoRail, having got some basics working already. However, while I've managed to check whether a Flash["message"] value has been set by a controller action, the BaseControllerTest class doesn't seem to store the output for a view at all, so whether I call RenderView or the action itself, nothing gets added to the Response.OutputContent data.
I've also tried calling InPlaceRenderView to try to get it to write to a StringWriter, and the StringWriter also seems to get nothing back - the StringBuilder that returns is also empty.
I'm creating a new controller instance, then calling
PrepareController(controller,"","home","index");
So far it just seems like the BaseControllerTest is causing any output to get abandoned. Am I missing something? Should this work? I'm not 100% sure, because while I'm also running these unit tests in MonoDevelop on Linux, although MonoRails is working OK there.
While I haven't got an ideal method for testing Views, this is possibly less important when ViewComponents can be tested adequately. To test views within the site itself, I can use Selenium. While in theory that can be made part of an NUnit test suite, that didn't run successfully under MonoDevelop in my tests (failing to start the connection to Selenium RC consistently, despite the RC interactive session working fine). However, the Selenium tests can be run as a set from Firefox, which is not too bad - unit testing with NUnit, then Integration/System testing scripting using a Selenium suite, and that setup will work in a Linux/MonoDevelop setup.
As for testing the underlying elements, you can check for redirections and check the flash value set or the like, so that's all fine, and for testing ViewComponents the part-mocked rendering does return the rendered output in an accessible form, so they've proved much easier to test in NUnit (with a base test class of BaseViewComponentTest) as follows:
[Test]
public void TestMenuComponentRendersOK()
{
var mc = new MenuComponent();
PrepareViewComponent(mc);
var dict = new System.Collections.Specialized.ListDictionary();
dict.Add("data",getSampleMenuData());
dict.Add("Name","testmenu");
// other additional parameters
mc.RenderComponent(mc,dict);
Assert.IsTrue(this.Output.Contains(""),"List items should have been added");
}