If I need to run only one test from class like
phpunit --filter someTest tests/ExampleTest.php
PHPUnit still initializes dataProviders for all tests in that class, which, in my case, takes plenty of time.
Is there a way to initialize dataProvider only for executed method?
If you use --group instead of --filter, only the tests of the selected group are initialized. That should also apply to data providers.
To do so, you have to add the #group annotation (fortunately this is possible per method and not only per class). If you still want to be able to execute all tests separately, put each one in its own group:
/**
* #test
* #group someTest
* #dataProvider someData
*/
public function someTest(...)
Related
I need to skip all the tests in the following cest class and currently I am skipping individual tests with #skip annotation. Is there any way I can skip execution at the class level itself, instead of individually skipping each test?
Currently I am skipping individual tests like this:
Class MyTests{
/**
* #skip Skip message
*/
public funtion test1(){
// Test steps
}
/**
* #skip Skip message
*/
public function test2(){
// Test steps
}
}
I tested it with Codeception 5 and #skip message works above class too.
I discovered a number of related issues and raised https://github.com/Codeception/Codeception/issues/6615
I am trying to set test expectations on a mock object that is created in a data provider and passed to my test method. This is useful because I can reused my data provider across different test cases and have the tests define what to expect on the mock. However, phpunit marks this test as risky when the case passes, but correctly fails the test when it does not pass. Is this a known thing that cannot be done?
I am using phpunit v9.3
Here is a contrived example to show the problem:
<?php
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class Test extends TestCase
{
public function provideMock(): array
{
return [
[$this->createMock(\DateTime::class)],
];
}
/** #dataProvider provideMock */
public function testMockPasses(MockObject $mock): void
{
$mock->expects($this->once())->method('format')->with('Y-m-d');
$mock->format('Y-m-d');
}
/** #dataProvider provideMock */
public function testMockFails(MockObject $mock): void
{
$mock->expects($this->once())->method('format')->with('Y-m-d');
$mock->format('Y-m-');
}
}
I would expect this to work fine as I am just passing the object to the method - all internal php stuff.
Try running PHPUnit with --verbose key - it may tell more about the reason of marking the test as risky.
I have a Symfony WebTestCase-extending PHP Test class and a DRY-trait. The test functions in my class #depend on the test functions in my trait, however I can't manage to execute the trait tests before the class tests. Is that possible?
trait TestTrait
{
/**
* #beforeClass
*/
public function testBeforeAnythingElseHappens()
{
/*...*/
}
/* more functions */
}
Test Class
class Test extends WebTestCase
{
use TestTrait;
/**
* #depends testBeforeAnythingElseHappens
*/
function testClassSpecificStuff()
{
/* ... */
}
}
First, see PHPUnit Manual - Appendix B. Annotations:
#beforeClass
The #beforeClass annotation can be used to specify static methods that should be called before any test methods in a test class are run to set up shared fixtures.
So, you should not use #beforeClass here - it is intended to allow setting up fixtures. In addition, the methods annotated as such should be static.
Second, see PHPUnit Manual - Appendix B. Annotations:
#depends
PHPUnit supports the declaration of explicit dependencies between test methods. Such dependencies do not define the order in which the test methods are to be executed but they allow the returning of an instance of the test fixture by a producer and passing it to the dependent consumers.
So yes, you could use the #depends annotation to declare dependencies between tests. Just remove the #beforeClass annotation:
trait TestTrait
{
public function testBeforeAnythingElseHappens()
{
}
}
class Test extends WebTestCase
{
use TestTrait;
/**
* #depends testBeforeAnythingElseHappens
*/
public function testClassSpecificStuff()
{
}
}
Third, a few words of advice (from my own experience):
Do not require tests to be run in a certain order.
If you arrange something in one test and need the same thing in another, just do it multiple times, do not worry too much about repeating yourself.
For reference, see:
http://blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling/
What does “DAMP not DRY” mean when talking about unit tests?
I am using php for testing my code. Here is an example:
/**
* #covers Calculator::
*/
class CalculatorTest extends PHPUnit_Framework_TestCase {
protected function setUp() { /* ... */ }
/**
* #covers Calculator::add
*/
public function testAddTwoIntegers() { /* ... */ }
/**
* #covers Calculator::multiply
*/
public function testMultiplyTwoIntegers() { /* ... */ }
}
However, my code is complicated and I want to get rid of #covers over individual test methods. How does php treat the following class when generating coverage reports:
/**
* #covers Calculator
*/
class CalculatorTest extends PHPUnit_Framework_TestCase {
protected function setUp() { /* ... */ }
public function testAddTwoIntegers() { /* ... */ }
public function testMultiplyTwoIntegers() { /* ... */ }
}
Notice that the #covers annotation over a class is still there but I have removed it from every method.
I am able to get coverage reports using this approach too but I have not seen an example of it anywhere, so I want to know if this is not a correct use.
Code Coverage Report:
2016-01-18 08:57:50
Summary:
Classes: 17.67% (56/317)
Methods: 0.33% (5/1520)
Lines: 0.60% (109/18094)
Class1:
Methods: 66.67% ( 2/ 3) Lines: 95.45% ( 21/ 22)
Class2:
Methods: 50.00% ( 3/ 6) Lines: 96.70% ( 88/ 91)
Indeed, setting the classname without the method name is the recommended #covers syntax.
Documentation here:
https://phpunit.readthedocs.io/en/8.5/annotations.html#covers
Annotation
#covers ClassName::methodName (not recommended)
#covers ClassName (recommended)
#covers ClassName<extended> (not recommended)
#covers ClassName::<public> (not recommended)
#covers ClassName::<protected> (not recommended)
#covers ClassName::<private> (not recommended)
#covers ClassName::<!public> (not recommended)
#covers ClassName::<!protected> (not recommended)
#covers ClassName::<!private> (not recommended)
#covers ::functionName (recommended)
When you ask:
How does php treat the following class when generating coverage reports
The answer is: Every line of the class mentioned in #covers executed during "any" of the tests in that TestCase will compute a +1 in the execution.
If you do real TDD and start first by writing the test, then writing the class, this is a perfect approach. Some of your lines in your public methods with branches will count 2 or more executions, and probably the lines inside each of the branches will count 1 execution.
Private methods will also count +n executions, while you won't write named tests for those methods, they will be called as a result of being helpers to the public methods.
When you say:
but I have not seen an example of it anywhere
I can tell that 90% of our tests use a #covers MyNiceClass annotation without specifying any method.
If you start by the test first, you normally won't mess up things. If you "need" that "MyNiceClass" is able to get something, you start by doing testGetSomething() in the test and set a basic expectation, then you write the public function getSomething() in the class and you end up having a one-to-one test for each method in 80% of the cases. The rest of the cases normally are multiple tests for the same method like for example testGetSomething() (happy path) and testGetSomethingThrowsExceptionWithInvalidParameter() (sad path).
In short
Yes, what you propose is correct, normal, usual and it is the recommended way to go according to the documentation.
Another reason (which was the reason in my case) is not using the complete class-name including the namespace.
// Should be like
#covers \App\Module\MyClass::doSomething
Why not simply run the test case and see the coverage with your changes? You risk getting down-voted as you are asking a question without trying anything.
From the PHPUnit manual:
The #covers annotation (see Table B.1) can be used in the test code to specify
which method(s) a test method wants to test. If provided, only the code
coverage information for the specified method(s) will be considered. Example
11.2 shows an example.
Table B1 Referenced above
What I am currently trying to do is to test the constructor of a class in an unit test.
I am not sure whether the instance of this object is a "god object", I would say it's not, since it only aggregates several other components.
Either way, I am open to a better design.
So the rough class diagram looks like this
World is the suspected god class. Its dependencies, ServiceProvider, CommandRegistry, EventHub and Environment are injected via its constructor.
In its constructor, World does the following things:
store its dependencies in private fields
register a hook ($this, 'onCommandIssued') with the eventHub so that the world receives notifications about all commands being executed not through the world instance itself (world having also a method executeCommand)
tell the environment to adopt the world: $this->environment->adoptWorld($this). The environment's role is to adapt the world to some of the realities of the running environment, for instance a web environment has some specific services which are not available in a console application environment (e.g. the "session" service)
notify via the event hub that the construction of the world has finished: $this->eventHub->notify(new WorldConstructedEvent($this));
Maybe this looks like a heavy constructor, but it simply is what is defined as "constructing the world".
The World is basically the gateway to send commands (as Data Transfer Objects, via World::executeCommand()) to which different services can register hooks.
Now to the problems/questions:
I am trying to unit-test this constructor, but I have to add a bunch of #uses annotations, which makes it feel like anything else but an unit test. What is it then, a functional test? Unit-testing World is awkward, testing anything else is really trivial and I don't see this problem emerging in any other test, which makes me ask myself why that is and how to improve the design.
Is World a god object? All it does is to aggregate other components and forward calls to them.
How to properly unit-test the methods of World? If I use lots of stubs and I dependency-inject them, is it still unit-testing?
This is for a domain-driven designed (complex) application and I am open to suggestions which would make the design better (testable and decoupled).
Please let me know in the comments if you need any more details.
As I don't know where this discussion will lead to, I may refine my questions.
I finally got to unit-test the class by setting up proper expectations and mock the dependencies:
<?php
namespace Common\World;
use TestFramework\TestCase;
class WorldTest extends TestCase
{
/**
* #test
* #covers \Common\World\World::__construct
* #uses \Common\World\World::setEventHub
* #uses \Common\World\Event\Adopted
*/
public function construction()
{
/** #var \Common\World\Environment $environmentStub |\PHPUnit_Framework_MockObject_MockObject */
$environmentStub = $this->getMockBuilder('Common\World\Environment')->getMock();
/** #var \Common\World\EventHub|\PHPUnit_Framework_MockObject_MockObject $eventHubStub */
$eventHubStub = $this->getMock('Common\World\EventHub');
$environmentStub->expects($this->once())
->method('adoptWorld')
->will($this->returnCallback(function (World $world) use ($eventHubStub) {
$world->setEventHub($eventHubStub);
return true;
}));
$eventHubStub->expects($this->once())
->method('trigger')
->with($this->isInstanceOf('Common\World\Event\Adopted'));
$this->assertInstanceOf('Common\World\World', new World($environmentStub));
}
/**
* #test
* #covers \Common\World\World::__construct
* #expectedException \RuntimeException
* #expectedExceptionMessage the environment has rejected this world for incompatibility reasons
*/
public function construction_rejected()
{
/** #var \Common\World\Environment $environmentStub */
$environmentStub = $this->getMockBuilder('Common\World\Environment')->getMock();
$environmentStub->expects($this->once())
->method('adoptWorld')
->will($this->returnValue(false));
new World($environmentStub);
}
}