AspectMock is working fine, except for mocking of a constructor.
As an example, using a very simple class:
class SimpleClass
{
public $var1;
public function __construct($var1)
{
$this->var1 = $var1;
}
}
With a very simple test:
public function testConstructorMock()
{
$mockedClass = test::double('SimpleClass')->make();
$mockedClass->var1 = 2;
$mocked = test::double('SimpleClass',[
'__construct' => $mockedClass,
]);
$mySimpleClass = new SimpleClass(0);
print_r($mySimpleClass);
}
The returned object ($mySimpleClass) has a null value rather than the mocked value.
Everything else works fine, just the mocking of the constructor is problematic. Any ideas how to correct this?
Related
I am very new to TDD. I am using phpunit 7.4x-dev. I have the following abstract class that I am trying to develop unit tests for.
use PDO;
abstract class Model {
protected static function getDB() {
static $db = null;
if ($db === null) {
$db = new PDO(ConfigDatabase::DSN, ConfigDatabase::USER, ConfigDatabase::PASSWORD);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return $db;
}
}
I have created the following test to get around the need to deal with the static protected method. And it works if I provide "ConfigureDatabase" class.
use PHPUnit\Framework\TestCase;
class ModelTest extends TestCase {
function newMockClass(){
$stub = new class() extends Model{
function getStaticMethod($methodName){
return self::$methodName();
}
};
return $stub;
}
public function testDatabaseExists() {
$stub = $this->newMockClass();
$db = $stub->getStaticMethod('getDB');
$this->assertInstanceOf(PDO::class,$db);
}
}
Since I do not want my tests to rely on any actual database, How would I fake the calls to PDO.
Following Dormilich suggestion I developed a database interface, just in case I decide later I do not want to use PDO.
interface CRUDImp {
function __construct($datbaseBridgeLikePDO);
...
}
Next I wrote my tests for the constructor. I used setup to make sure I was starting with a fresh mock of \PDO.
class PDOWrapperTest extends TestCase {
private $pdoMock;
private $db;
function setup() {
$this->pdoMock = $this->createMock('\PDO');
$this->db = new PDOWrapper($this->pdoMock);
}
public function testWrapperExists() {
$this->pdoMock->method('getAttribute')->willReturn(\PDO::ERRMODE_EXCEPTION);
$db = new PDOWrapper($this->pdoMock);
$x = $db instanceof CRUDImp;
$this->assertTrue($x);
}
/**
* #expectedException \Exception
*/
public function testNonPDOPassedToConstructor() {
$mock = $this->createMock('\Exception');
$x = new PDOWrapper($mock);
}
...
}
Since PHP is loosely typed I check to make sure that the class passed to the constructor was an instance of \PDO. I implemented the concrete class as follows
class PDOWrapper implements CRUDImp {
private $pdo;
private $dataOutputType = \PDO::FETCH_ASSOC;
public function __construct($pdo) {
if (!($pdo instanceof \PDO)) {
throw new \Exception("PDOWrapper must be passed instance of \PDO");
}
$attr_Errmode = $pdo->getAttribute(\PDO::ATTR_ERRMODE);
if ($attr_Errmode !== \PDO::ERRMODE_EXCEPTION) {
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
$this->pdo = $pdo;
}
...
}
Now that I have an independent database wrapper the original Model tests are at the moment trivial and no longer needed. The abstract class Model was modified as follows:
abstract class Model {
protected $database=null;
function __construct(CRUDWrapper $database) {
$this->database = $database;
}
...
}
So for those not familiar with dependency injection I found the following links helpful:
http://php-di.org/doc/understanding-di.html
https://codeinphp.github.io/post/dependency-injection-in-php/
https://designpatternsphp.readthedocs.io/en/latest/Structural/DependencyInjection/README.html
Hope this shortens someone's work.
I am learning codeception and I wonder what is the difference between stubs and fixtures.
Both help me to load well-defined data and kepp tessts simple.
But when do I use
\Codeception\Util\Stub and when do I use
\Codeception\Util\Fixtures
So a stub is what Codeception uses to mock objects. In short, mocking is creating objects that simulate the behaviour of real objects.
Here is an example:
class UpdateBalance
{
public $balanceRepository;
public function __construct(BalanceRepositoryInterface $balanceRepository)
{
$this->balanceRepository = $balanceRepository;
}
public function subtract($amount, $id)
{
$updatedAmount = $this->balanceRepository->subtract($amount, $id);
if ($updatedAmount < 0) {
throw NegativeBalanceException($updatedAmount, $id);
}
return $updatedAmount;
}
}
class UpateBalanceTest extends PHPUnit_Framework_TestCase
{
public function testSubtractThrowsNegativeBalanceException()
{
$balanceRepository = Stub::make(
'BalanceRepositoryInterface'
array(
'subtract' => Stub::atLeastOnce(function() { return -100 })
)
);
$updateBalance = new UpdateBalance($balanceRepository);
$this->expectException(NegativeBalanceException::class);
$updateBalance->subtract(100, 1);
}
}
Note that we don't have a BalanceRepsository class. We have used Codeception stubs and pretended that the BalanceRepository class exists. By pretending it exists we can test the functionality of the UpdateBalance::subtract function by checking that the NegativeBalanceException is thrown.
Fixtures on the other hand would be for sharing test data throughout all your tests. If we use the UpdateBalance::subtract() example again, we could stress test the amount field ensuring it throws the correct exception depending on the amount being passed through:
// In some bootstrap or setup function
Fixtures::add('zero-amount', 0);
Fixtures::add('negative-amount', -1);
Fixtures::add('string-negative-amount', '-1');
class UpdateBalance
{
// ...
public function subtract($amount, $id)
{
if ($amount < 0) {
throw new
}
// ...
}
}
class UpateBalanceTest extends PHPUnit_Framework_TestCase
{
// ...
public function testSubtractThrowsCantSubtractNegativeAmountException()
{
$balanceRepository = Stub::make(
'BalanceRepositoryInterface'
);
$updateBalance = new UpdateBalance($balanceRepository);
$this->expectException(CantSubtractNegativeAmountException::class);
$updateBalance->subtract(Fixture::get('negative-amount'), 1);
}
}
Now we can use our pre-defined fixtures throughout all our tests. I would like to point out that using fixtures in the above example would probably be overkill, but for more complex test data like checking hexadecimal values are valid then it would be a lot more useful.
I am trying to test this function in a Laravel controller:
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
$project = $this->project->create(Input::all());
if ( $errors = $project->errors()->all() ) {
return Redirect::route('projects.create')
->withInput()
->withErrors($errors);
}
return Redirect::route('projects.index')
->with('flash', Lang::get('projects.project_created'));
}
My (wrong) test looks like this:
public function testStoreFails()
{
$this->mock->shouldReceive('create')
->once()
->andReturn(Mockery::mock(array(
false,
'errors' => array()
)));
$this->call('POST', 'projects');
$this->assertRedirectedToRoute('projects.create');
$this->assertSessionHasErrors();
}
The problem is, basically, that Ardent sets $project to false when the validation fails, but it also sets errors on that same object, that can be retreived with ->errors()->all().
I'm quite lost trying to find out what to return in the mock.
Note: The constructor injects the model:
public function __construct(Project $project)
{
$this->project = $project;
$this->beforeFilter('auth');
}
– Edited by following comments in answer –
If I'm understanding what you are trying to do properly, you could do this:
Mock the create() method to return a mocked Project.
Mock the save() method to return false.
Mock a MessageBag instance, which is the object that errors() would return. This mock should have a mocked all() method.
Make the mocked errors() method to return the MessageBag mock.
Assuming $this->mock is a mock of the Project class here:
// given that $this->mock = Mockery::mock('Project')
public function testStoreFails()
{
// Mock the create() method to return itself
$this->mock->shouldReceive('save')->once()->andReturn(false);
// Mock MessageBag and all() method
$errors = Mockery::mock('Illuminate\Support\MessageBag');
$errors->shouldReceive('all')->once()->andReturn(array('foo' => 'bar'));
// Mock errors() method from model and make it return the MessageBag mock
$this->mock->shouldReceive('errors')->andReturn($errors);
// Proceed to make the post call
$this->call('POST', 'projects');
$this->assertRedirectedToRoute('projects.create');
$this->assertSessionHasErrors();
}
I am trying to mock a method call which goes something like this:
rapContext.getSysInfo().get(key)
The getSysInfo() method returns a ConcurrentHashMap.
Here is what I have done:
Class ABCTest {
#Cascading RapContext context;
#Test
doTest() {
new Expectations() {
{
rapContext.getSysInfo().get(anyString);
result = new UserPrefCtxObject();
}
}
}
With this I get a NullPointerException on rapContext.getSysInfo(). Call to getSysInfo() returns null. If I call any other method which does not return a collection, for instance rapContext.getDomain() everything working fine.
I am not sure what I am missing.
Thanks
The code example is not complete however you are likely running into some issue associated with accidentally mocking Map. If a Map (or any part of the Collection framework) is mocked then a lot of things will break. I could not reproduce your problem as any attempt to mock RapContext using #Cascading resulted in a stack over flow.
You could partially mock RapContext instead and then either return a real or mocked Map. When I run into similar issues I generally get around them using either #Injectable to only mock an instance of a class or using partial mocks.
Here is an approach that will let you mock getSysInfo:
public class RapContextTest {
#Injectable ConcurrentHashMap<String, Object> mockedMap;
#Test
public void testContext() {
RapContext context = new RapContext();
new MockUp<RapContext>(){
#Mock
public ConcurrentHashMap getSysInfo(){
return mockedMap;
}
};
new NonStrictExpectations() {
{
mockedMap.get(anyString);
result = "Success";
}
};
Object value = context.getSysInfo().get("test");
System.out.println(value);
}
}
My following straight forward test doesn't pass (Though I feel it should). Either I am missing something or is not clear of Property.value constraint. please help me in understanding concept of property.value constraint.
public interface ISomeInterface
{
void SomeMethod(string x, string y);
}
public class SomeClassTest
{
[Test]
public void SomeMethodTest()
{
MockRepository mocks = new MockRepository();
ISomeInterface mockservice = mocks.StrictMock<ISomeInterface>();
using (mocks.Record())
{
mockservice.SomeMethod("xValue", "yValue");
LastCall.Constraints(Property.Value("x", "xValue"),
Property.Value("y", "yValue"));
}
mockservice.SomeMethod("xValue", "yValue");
mocks.Verify(mockservice);
}
}
Exception raised:
Rhino.Mocks.Exceptions.ExpectationViolationException : ISomeInterface.SomeMethod("xValue", "yValue"); Expected #0, Actual #1.
ISomeInterface.SomeMethod(property 'x' equal to xValue, property 'y' equal to yValue); Expected #1, Actual #0.
I would recommend you the following syntax (AAA syntax):
// arrange
var mockservice = MockRepository.GenerateMock<ISomeInterface>();
// act
mockservice.SomeMethod("xValue", "yValue");
// assert
mockservice.AssertWasCalled(
x => x.SomeMethod("xValue", "yValue")
);
This sample class illustrates the options for asserting methods were called with appropriate properties:
public class UsesThing
{
private IMyThing _thing;
public UsesThing(IMyThing thing)
{
_thing = thing;
}
public void DoTheThing(int myparm)
{
_thing.DoWork(myparm, Helper.GetParmString(myparm));
}
public void DoAnotherThing(int myparm)
{
AnotherThing thing2 = new AnotherThing();
thing2.MyProperty = myparm + 2;
_thing.DoMoreWork(thing2)
}
}
Using simple values for assertions may work for methods like the DoTheThing method which uses value types:
[Test]
public void TestDoTheThing()
{
IMyThing thing = MockRepository.GenerateMock<IMyThing>();
UsesThing user = new UsesThing(thing);
user.DoTheThing(1);
thing.AssertWasCalled(t => t.DoWork(1, "one");
}
However, if you need to create an object in your method and pass it as a parameter like in the DoAnotherThing method, this approach will not work since you will not have a reference to the object. You have to check the property values of the unknown object, like this:
[Test]
public void TestDoAnotherThing()
{
IMyThing thing = MockRepository.GenerateMock<IMyThing>();
UsesThing user = new UsesThing(thing);
user.DoAnotherThing(1);
thing.AssertWasCalled(t => t.DoMoreWork(null), t => t.IgnoreArguments().Constraints(Property.Value("MyProperty", 3))));
}
The new Rhino syntax would look like the following, but I am crashing VS 2008 when I use it:
thing.AssertWasCalled(t => t.DoMoreWork(Arg<AnotherThing>.Matches(Property.Value("MyProperty", 3))));