-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Command factory tests #167
Command factory tests #167
Conversation
if (!class_exists($className)) { | ||
throw new Exception('Command "' . $commandName . '" not found.'); | ||
} | ||
} | ||
|
||
/** @var AbstractCommand $instance */ | ||
// TODO dependencies like $config should be injected into constructor |
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.
Not exactly. At first, we have no DI mechanism in Magallanes, and as @andres-montanez said in one of issue, we shouldn't use external dependencies as long as Magallanes lives also as a Pear package.
But injecting things in many DI mechanisms can be done by constructor or via proper methods. Sometimes it's even necessary to inject them like 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.
Can you please link to that issue? I don't understand why you're referring to pear. Do you mean Config
when you write about external dependencies?
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.
No, I meant some DI mechanism, like Sf2 Dependency Injection, or any other, loaded by composer dependency that we could use. We can, of course, write our own DI.
Issue I mentioned about is: #88
It's only short sentence but, I don't know why, I keep that in mind.
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 don't want to introduce ServiceLocator or other external libs, but the constructor is a common place to inject dependencies that are mandatory. Right now, the configuration is injected with a setter even when the Command doesn't need it. It means there is a setter which isn't needed in every Command class nor does every Command has a dependency to extend AbstractCommand
.
The suggested todos are future talk, because injecting only the needed dependencies would result into changing the factory.
If there are already some rules about what this project doesn't want to introduce, a text-information like a contribution.md would be nice so that devs creating a PR can follow that guideline. Since we already introduced unit tests together, one contribution rule could be, that a PR must contain unit tests for the new code.
BTW: I'm glad the todo comments were noticed by someone.
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.
Of course, that's what I was talking about. I've wanted only note that not everything in injection mechanisms should be done by constructor. In this part it can be done,even it should be done, because in the other way, get
method won't work properly.
And I'm glad too that someone makes such sugestions.
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.
@eps90 Does the comment of @andres-montanez in #88 really mean that no external PHP packages should be used? That issue is about a feature which can only be implemented using a non-standard PHP extension like ncurses.
Also, does Magallanes really live as a PEAR package? It's neither mentioned in the documention nor can I see a PEAR package file (package.xml).
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.
@GodsBoss By PHP packages @andres-montanez meant composer dependencies and I don't see any reason why should we need ncurses for progress bar (if you're talking about #88).
Of course I mistyped my comment and I meant phar package :)
The one thing bother me for a long time - why did you create the classes physically? Can't you just mock them? |
What do you suggest how we should handle this for the current and future tests of object creating factories in Magallanes? |
Well there is a way to do this, and I almost have the solution but one PHPUnit bug stopped me... Here are some details:
Where's the bug?
|
I know Mockery and tested it before. It offeres lot of functionalities to mock static methods and instances created inside a methods, that are not injected. When I created the merged PR for introducing unit tests to Magallanes, I decided against Mockery. Unit tests can be a good way to show bad testable code while showing what can be improved. Who needs DI when a class can be mocked inside another method. Let's make every method static because we can easily use Mockery. I agree that finding a way for replacing Dummy classes would be nice, but I guess there are open questions. What are we trying to accomplish with unit tests on current code and what are the plans for the current code? Do we bend our tests to the current code first? Is new introduced code and its tests build the same way like the current? |
I'm not saying we need to use Mockery to test untestable code. I meant only we can use it because it doesn't contain the bug the PHPUnit has. |
Meanwhile I've found temporary solution to workaround the bug.
$this->getMockBuilder('MyAbstractClass')
->setMockClassName('MyNamespace\MyClass')
->getMock();
$mock = $this->getMockBuilder('MyAbstractClass')
->setMockClassName('MyClass')
->getMock();
class_alias('MyClass', 'MyNamespace\MyClass');
$this->assertInstanceOf('MyClass', $mock); // true
$this->assertInstanceOf('MyNamespace\MyClass', $mock); // true
$this->assertInstanceOf('MyAbstractClass', $mock); // also true |
And here's how your tests gonna look without any additional classes: public function testGetCustomCommand()
{
$this->getMockBuilder('Mage\Command\AbstractCommand')
->setMockClassName('MyCommand')
->getMock();
class_alias('MyCommand', 'Command\MyCommand');
$command = Factory::get('my-command', $this->config);
$this->assertInstanceOf('Command\\MyCommand', $command);
}
/**
* @expectedException \Exception
* @expectedExceptionMessage The command MyInconsistentCommand must be an instance of Mage\Command\AbstractCommand.
*/
public function testGetInconsistencyException()
{
$this->getMockBuilder('Command\MyInconsistentCommand')
->getMock();
Factory::get('my-inconsistent-command', $this->config);
} How do you like it? |
I did class_alias as workaround before too, since I had to test similar code too. It was about creating instances inside a method. But it's still a workaround. Because of your argument about the possible rising amount of Dummy classes in the future, I'm with you about finding a way to remove the Dummies/substitudes. I'm working with PHPUnit 4.5 currently and its support of Prophecy I dig into that and look if it can help to find a solution. We're at the start of adding unit tests to Magallanes and it would be easy to rise the version in |
Good point. I totally forgot that in PHPUnit 4.5 mocks can be used with Prophecy. I'll test that and will let you know ASAP. |
Well saddly, |
When life gives you lemons, then |
Thanks for comment indicating that this is temporary solution. I'll test that tomorrow when I'll have access to my laptop and I'll give you proper feedback :-) |
|
||
/** | ||
* current workaround | ||
* @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/134 |
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.
use @link
instead of @see
.
@see
is for documentation links, like other methods, classes, etc.
@link
is purely for hyperlinks
Please add PHPUnit's coverage annotations, because I can see that you unintentionally cover |
Annotations are now added/fixed. |
Remove "covers" annotations for static methods
Everyhitngs seems great now, thanks for merging my PR and for your support, @SenseException. Merging! :) |
I was reviewing the project code to check which classes can be tested easily (#44), but I'm afraid there will be bigger refactoring steps in the future before many classes of the project can be tested.
For now, I contribute small tests of the command factory, creating build in and custom commands. For custom commands, I created some dummy commands to be able to check exceptions and returned command instances.
I guess next time will be a PR with refactored code.