PHPUnit Stub does not return needed value - php

I have the following unit test but I don't get back the needed values. Maybe I don't understand how this works correctly.
class TestClass
{
public function getData()
{
$id = 1123;
return $id;
}
}
class Test_ClassTesting extends PHPUnit_Framework_TestCase
{
public function test_addData()
{
$stub = $this->getMock('TestClass');
$stub
->expects($this->any())
->method('getData')
->will($this->returnValue('what_should_i_put_here_to_get id from TESTCLASS'));
$y = $stub->getData();
}
}

As the commenters have said, you simply return the value desired.
class TestClass
{
public function getData()
{
$id = 1123;
return $id;
}
}
class Test_ClassTesting extends PHPUnit_Framework_TestCase
{
public function test_addData()
{
$stub = $this->getMock('TestClass'); // Original Class is not used now
$stub
->expects($this->any())
->method('getData')
->will($this->returnValue(4444)); // Using different number to show stub works, not actual function
$this->assertEquals(4444, $stub->getData());
}
public function test_addDataWithoutStub()
{
$object = new TestClass();
$this->assertEquals(1123, $object->getData());
}
}

Related

How to stub/mock return value of a function in php unit test

When trying to stub a simple function based on the phpunit documentation here, it doesn't seem to do anything.
<?php declare(strict_types=1);
class A {
public static function func() {
$helperData = A::helper();
return $helperData + 1;
}
public static function helper() {
return 5;
}
}
Test class
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class ATest extends TestCase
{
public function testFunc(): void
{
$stub = $this->createStub(A::class);
$stub->method('helper')
->willReturn(2);
$result = A::func();
$this->assertEquals(3, $result); // actual result is 6 not 3--why?
}
}
The stubbed function helper doesn't return 2 as I specified. Why is this, and how can I successfully mock the return value of the function?
You should use $stub object instead of A class, to get the stubbed function result. You should use non-static method to use this.
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
class A {
public function func() {
$helperData = $this->helper();
return $helperData + 1;
}
public function helper() {
return 5;
}
}
final class ATest extends TestCase
{
public function testFunc(): void
{
$stub = $this->createStub(A::class);
$stub->method('helper')
->willReturn(2);
$stub->method('func')
->willReturn($stub->helper() + 1);
$result = $stub->func(); // Use `$stub->`
$this->assertEquals(3, $result); // OK
}
}
Output:
OK (1 test, 1 assertion)
EDIT
To use the original code for func, you could make it static, and use a A instance as parameter. This A instance could be $stub (because $stub is a A&Stub instance).
class A {
public static function func(A $obj) {
$helperData = $obj->helper();
return $helperData + 1;
}
public function helper() {
return 5;
}
}
final class ATest extends TestCase
{
public function testFunc(): void
{
$stub = $this->createStub(A::class);
$stub->method('helper')
->willReturn(2);
$result = A::func($stub);
$this->assertEquals(3, $result);
}
}
Output:
OK (1 test, 1 assertion)

Switch visibility in php if parameter

I'm wondering if its possible to switch the visibility in PHP. Let me demonstrate:
class One {
function __construct($id){
if(is_numeric($id)){
//Test function becomes public instead of private.
}
}
private function test(){
//This is a private function but if $id is numeric this is a public function
}
}
Is such thing even possible?
I would use an abstract class with two implementing classes: One for numeric and one for non-numeric:
abstract class One {
static function generate($id) {
return is_numeric($id) ? new OneNumeric($id) : new OneNonNumeric($id);
}
private function __construct($id) {
$this->id = $id;
}
}
class OneNumeric extends One {
private function test() {
}
}
class OneNonNumeric extends One {
public function test() {
}
}
$numeric = One::generate(5);
$non_numeric = One::generate('not a number');
$non_numeric->test(); //works
$numeric->test(); //fatal error
It can be faked up to a point with magic methods:
<?php
class One {
private $test_is_public = false;
function __construct($id){
if(is_numeric($id)){
$this->test_is_public = true;
}
}
private function test(){
echo "test() was called\n";
}
public function __call($name, $arguments){
if( $name=='test' && $this->test_is_public ){
return $this->test();
}else{
throw new LogicException("Method $name() does not exist or is not public\n");
}
}
}
echo "Test should be public:\n";
$numeric = new One('123e20');
$numeric->test();
echo "Test should be private:\n";
$non_numeric = new One('foo');
$non_numeric->test();
I haven't thought about the side effects. Probably, it's only useful as mere proof of concept.

How get method from another class method

I have two class es
class Pet {
public $pet = null;
public function setPet(){}
public function getPet(){}
}
and
class B {
public $cat = 'cat';
public $dog = 'bog';
public function cat()
{
$pet = new Pet();
$pet->pet = $this->cat;
}
public function dog()
{
$pet = new Pet();
$pet->pet= $this->dog;
}
}
Can I get this:
$pet = new Pet();
$pet->setPet()->dog();
$pet->getPet(); //dog
I don't believe you can. You could make class B extends Pet. That will allow you to call the functions from the class Pet. Read up on object inheritance, that might help! http://php.net/manual/en/language.oop5.inheritance.php
You can simply extend Class Pet on Class B to call functions from the Pet class. So Class B inherits the functions of Pet.
Class B extends Pet {
// class B functions here...
}
I laughed while I'm writing down my code here..
<?php
class Pet {
public $name;
public function setName($string) {
$this->name = $string;
}
public function getName() {
return $this->name;
}
}
class Dog extends Pet {
public function bark() {
echo "Arf arf!";
}
}
class Cat extends Pet {
public function meow() {
echo "Meoooww~ purrr~";
}
}
$dog = new Dog();
$dog->setName("Jacob");
$dog->bark(); //Arf arf!
echo "Good job, ".$dog->getName()."!"; //Good job, Jacob!
?>
sir you cant call $pet->setPet()->dog() with ->dog() since setPet() is a function and not an object.. just like they said, the right thing to do with your code is to extend it as a super class and declare a Dog Class as the child class..
My variant
class Pet {
public $pet = null;
public function setPet($pet = null)
{
if (is_null($pet)) {
return new B($this);
} else {
$this->pet = $pet;
return $this;
}
}
public function getPet()
{
return $this->pet;
}
}
class B {
protected $pet = null;
protected $cat = 'cat';
protected $dog = 'bog';
public function __construct(Pet $pet)
{
$this->pet = $pet;
}
public function cat()
{
$this->pet->setPet($this->cat);
return $this->pet;
}
public function dog()
{
$this->pet->setPet($this->dog);
return $this->pet;
}
}
$pet = new Pet();
$pet->setPet()->cat();
var_dump($pet->getPet());

PHP Method Chaining: Calling one method before allowing other methods to be chained

Consider the following class
class myClass {
private $model;
public function update($input) {
return $this->model->update($input);
}
public function find($id) {
$this->model = ORMfind($id);
}
}
How do I prevent
$myClass = new myClass;
$myClass->update($input);
The problem isn't HOW to use the above code but how to make update() a method only callable after find().
EDIT: I changed what my method does so it was more clearly understood that I need to do one method (find()) before another (update())
You could add a flag to your code like so:
class myClass {
private $model;
private $canUpdate = 0;
public function update($input) {
if ($canUpdate === 0) return; // or throw an exception here
return $this->model->update($input);
}
public function find($id) {
$this->model = ORMfind($id);
$canUpdate = 1;
}
}
Setting the flag $canUpdate will caution the update() method to react accordingly. If update() is called, you can throw an exception or exit out of the method if the flag is still 0.
To prevent from returning null value by get :
public function get() {
if (isset($this->value)) return $this->value;
else echo "please give me a value ";
}
You can also create a construct:
function __construct($val){
$this->value=$val;
}
and then give a value to your $value without using set() method:
$myClass=new myClass(10);
Outputting text, returning void, I think all of this is wrong. When you do not expect something to happen, you should throw an exception:
class MyClass {
private $canUpdate = false;
public function find($id) {
// some code...
$this->canUpdate = true;
}
public function canUpdate() {
return $this->canUpdate;
}
private function testCanUpdate() {
if (!$this->canUpdate()) {
throw new Exception('You cannot update');
}
}
public function update($inpjut) {
$this->testCanUpdate();
// ... some code
}
}
Now you can do:
$obj = new MyClass();
try {
$obj->update($input);
} catch (Exception $e) {
$obj->find($id);
$obj->update($input);
}
The proper way to make sure ->update() can only be called when the model has been initialized is to turn it into a dependency:
class myClass
{
private $model;
public function __construct($id)
{
$this->model = ORMfind($id);
}
public function update($input) {
return $this->model->update($input);
}
}
$x = new myClass('123');
Alternatively, if you have multiple find operations, you could introduce them as static constructor methods:
class myClass
{
private $model;
private function __construct($model)
{
$this->model = $model;
}
public function update($input) {
return $this->model->update($input);
}
public static function find($id)
{
return new self(ORMfind($id));
}
}
$x = myClass::find('123');
Update
Tackling your immediate problem can be done by a simple check:
public function update($input) {
return $this->model ? $this->model->update($input) : null;
}

PHP Observer Pattern, Issue

Bellow is a PHP script.
I tried to implement the Observer pattern (without MVC structure)... only basic.
The error which is encountered has been specified in a comment.
First I tried to add User objects to the UsersLibrary repository. There was a error such as User::update() does not exists or something.
Why is that error encountered? What fix should be applied and how?
interface IObserver {
public function update(IObservable $sender);
}
interface IObservable {
public function addObserver(IObserver $obj);
public function notify();
}
class UsersLibrary implements IObservable {
private $container;
private $contor;
//private $z;
public function __construct() {//IObserver $a) {
$this->container = array();
$this->contor = 0;
echo "<div>[constructing UsersLibrary...]</div>";
$this->addObserver(new Logger());
//$this->z = $a;
}
public function add($obj) {
echo "<div>[adding a new user...]</div>";
$this->container[$this->contor] = $obj;
$this->contor++;
$this->notify();
}
public function get($index) {
return $this->container[$index];
}
public function addObserver(IObserver $obj) {
$this->container[] = $obj;
}
public function notify() {
echo "<div>[notification in progress...]</div>";
foreach($this->container as $temp) {
//echo $temp;
#################################################################
$temp->update(); //--------ERROR
//Fatal Error: Call to a member function update() on a non-object.
#################################################################
}
//$this->container[0]->update();
//$this->z->update($this);
}
}
class User {
private $id;
private $name;
public function __construct($id, $name) {
$this->id = $id;
$this->name = $name;
}
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
}
class Logger implements IObserver {
public function __construct() {
echo "<div>[constructing Logger...]</div>";
}
public function update(IObservable $sender) {
echo "<div>A new user has been added.</div>";
}
}
$a = new UsersLibrary(); //new Logger());
//$a->add(new User(1, "DemoUser1"));
//$a->add(new User(2, "DemoUser2"));
$a->add("Demo");
echo $a->get(0);
//echo $a->get(0)->getName();
Your User class is not implementing interface IObserver and therefore is not forced to have the method update().
You have to instantiate a new User() in order to add it to the UsersLibrary:
$library = new UsersLibrary();
$user = new User(1, "Demo");
$library->add($user);
Also, you are mixing Users and Loggers into your UsersLibrary container. Maybe think about separating the containers for them?
You are passing a string instead of an object in your $a->add() call. You should either pass in an object, or alter the code in UserLibrary::add() to wrap it's argument in an appropriate object (or do an object lookup of it sees a string, for instance find a user with that name).
$user = new User(1, "Demo");
$a = new UsersLibrary();
$a->add($user);

Categories