How to create class variables in a PHPSpec spec file that can be used for all examples in the spec - laravel

I have a PHPSpec class with many examples. I want to be able to create class variables in the spec class that can be used by any example function in the class.
Below is a very simplified version:
class ThingImTestingSpec extends ObjectBehavior
{
private $common_variables_array = [
'property_1' => value_1,
'property_2' => 'Value 2'
];
function it_finds_a_common_property()
{
$object_1 = new ConstructedObject;
$this->find_the_common_property($object_1)->shouldReturn($this->common_variables_array['property_1']);
}
}
The issue lies in how PHPSpec (cleverly) instantiates and references the class under test. References to $this in the spec methods actually refer to the test object, not the spec class itself.
But that means that trying to reference class variables using $this->class_variable references class variables on the test object, not the spec.
So. How to create a set of variables in the scope of the spec class itself that can be accessed by the examples at runtime?
Things I've tried:
Placing the class variables within a constructor – still can't be accessed by the examples
Using beConstructedWith – requires altering the class under test just so it can be tested. Not a clean solution.
When the common objects I want to reference are database records, I can reference them by id (or other properties) using Eloquent, building a collection or class object from the Model each time. This works, but is time-consuming, as I need to build the collection or object in every spec function. I'd like to build these collections and objects once, when the spec class is instantiated, and reference them throughout the class.
Things I haven't tried yet:
Creating a third object outside the scope of both the spec class and the class under test to house the universal objects and variables, which can be accessed by the spec class methods (the examples) at runtime. This solution could work, but it adds a layer to the specs that I'd like to avoid if there's a cleaner solution.
NB: I'm not looking for "alternatives" to going about testing in the way outlined above, unless they still suit the broader needs. The example is extremely pared down. In practice, I'm extending LaravelObjectBehavior (https://github.com/BenConstable/phpspec-laravel), creating records in a test database using the spec's constructor via Factory and Faker classes (https://github.com/thephpleague/factory-muffin), and destroying them after the test (League\FactoryMuffin\Facade::deleteSaved() in the spec's destructor). I want to be able to reference objects represented by the Model (and created by FactoryMuffin) in any number of spec functions, so I don't have to recreate these objects and collections in every spec function. And yes, I'm aware that this steps outside the realm of "spec" testing, but when an app is tethered to a model, objects that interact with the data layer are still "speccable", it can be argued.
I'm currently using phpspec 2.2.1 and Laravel 4.2

We currently use PHPSpec v3 in our software. Please use let method to declare common things. Quick example:
<?php
class ExampleSpec extends \PhpSpec\ObjectBehavior
{
private $example; // private property in the spec itself
function let()
{
$this->example = (object) ['test1' => 'test1']; // setting property of the spec
parent::let();
}
function it_works()
{
var_dump($this->example); // will dump: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
}
function it_works_here_as_well()
{
var_dump($this->example); // will dump same thing as above: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
$this->example = (object) ['test2' => 'test2']; // but setting here will be visible only for this example
}
function it_is_an_another_example()
{
var_dump($this->example); // will dump same thing first two examples: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
}
}

Found the answer. Explicitly declare the class variables as static and they can be accessed by the methods in the spec class:
class ThingImTestingSpec extends ObjectBehavior
{
private static $common_variables_array = [
'property_1' => value_1,
'property_2' => 'Value 2'
];
function it_finds_a_common_property()
{
$object_1 = new ConstructedObject;
$this->find_the_common_property($object_1)->shouldReturn($this::$common_variables_array['property_1']);
}
}
This is working for arrays as well as objects that represent database records built using Eloquent, e.g.
class LaravelAppClassImTestingSpec extends LaravelObjectBehavior
{
private static $Order_1;
function __construct()
{
$Order_1 = \Order::find(123);
}
function it_tests_a_thing()
{
//(the method has access to the static class variable via
//$this::$Order_1
}
}

Related

Yii2: How to set default attribute values in ActiveRecord?

This may seem like a trivial question, however all of the obvious solutions that I can think of have their own flaws.
What we want is to be able to set any default ActiveRecord attribute value for new records only, in a way that makes it readable before and during validation and does not interfere with derived classes used for search.
The default values need to be set and ready as soon as we instantiate the class, so that (new MyModel)->attr returns the default attr value.
Here are some of the possibilities and the problems they have:
A) In MyModel override the init() method and assign default value when isNewRecord is true like so:
public function init() {
if ($this->isNewRecord) {
$this->attr = 'defaultValue';
}
parent::init();
}
Problem: Search. Unless we explicitly unset our default attribute in MySearchModel (very error-prone because it is too easy to forget), this will also set the value before calling search() in the derived MySearchModel class and interfere with searching (the attr attribute will already be set so search will be returning incorrect results). In Yii1.1 this was resolved by calling unsetAttributes() before calling search(), however no such method exists in Yii2.
B) In MyModel override the beforeSave() method like so:
public function beforeSave($insert) {
if ($insert) {
$this->attr = 'defaultValue';
}
return parent::beforeSave();
}
Problem: Attribute is not set in unsaved records. (new MyModel)->attr is null. Worse yet, even other validation rules that rely on this value will not be able to access it, because beforeSave() is called after validation.
C) To ensure the value is available during validation we can instead override the beforeValidate() method and set the default values there like so:
public function beforeValidate() {
if ($this->isNewRecord) {
$this->attr = 'defaultValue';
}
return parent::beforeValidate();
}
Problem: Attribute is still not set in unsaved (unvalidated) records. We need to at least call $model->validate() if we want to get the default value.
D) Use DefaultValidator in rules() to set a default attribute value during validation like so:
public function rules() {
return [
[
'attr', 'default',
'value' => 'defaultValue',
'on' => 'insert', // instantiate model with this scenario
],
// ...
];
}
Problem: Same as B) and C). Value is not set until we actually save or validate the record.
So what is the right way to set default attribute values? Is there any other way without the outlined problems?
There's two ways to do this.
$model => new Model();
Now $model has all the default attributes from the database table.
Or in your rules you can use:
[['field_name'], 'default', 'value'=> $defaultValue],
Now $model will always be created with the default values you specified.
You can see a full list of core validators here http://www.yiiframework.com/doc-2.0/guide-tutorial-core-validators.html
This is a hangup with Yii's bloated multi-purpose ActiveRecords
In my humble opinion the form models, active records, and search models would be better off split into separate classes/subclasses
Why not split your search models and form models?
abstract class Creature extends ActiveRecord {
...
}
class CreatureForm extends Creature {
public function init() {
parent::init();
if ($this->isNewRecord) {
$this->number_of_legs = 4;
}
}
}
class CreatureSearch extends Creature {
public function search() {
...
}
}
The benefits of this approach are
You can easily cater for different validation, set up and display cases without resorting to a bunch of ifs and switches
You can still keep common code in the parent class to avoid repetition
You can make changes to each subclass without worrying about how it will affect the other
The individual classes don't need to know about the existence of any of their siblings/children to function correctly
In fact, in our most recent project, we are using search models that don't extend from the related ActiveRecord at all
I know it is answered but I will add my approach.
I have Application and ApplicationSearch models. In Application model I add init with a check of the current instance. If its ApplicationSearch I skip initializations.
public function init()
{
if(!$this instanceof ApplicationSearch)
{
$this->id = hash('sha256', 123);
}
parent::init();
}
also as #mae commented below you can check for existence of search method in current instance, assuming you didn't add any method with name search to the non-search base model so the code becomes:
public function init()
{
// no search method is available in Gii generated Non search class
if(!method_exists($this,'search'))
{
$this->id = hash('sha256', 123);
}
parent::init();
}
I've read your question several times and I think there are some contradictions.
You want the defaults to be readable before and during validation and then you try init() or beforeSave(). So, assuming you just want to set the default values in the model so they can be present during the part of the life cycle as long as possible and not interfere with the derived classes, simply set them after initialising the object.
You can prepare separate method where all defaults are set and call it explicitly.
$model = new Model;
$model->setDefaultValues();
Or you can create static method to create model with all default values set and return the instance of it.
$model = Model::createNew();
Or you can pass default values to constructor.
$model = new Model([
'attribute1' => 'value1',
'attribute2' => 'value2',
]);
This is not much different from setting the attributes directly.
$model = new Model;
$model->attribute1 = 'value1';
$model->attribute2 = 'value2';
Everything depends on how much transparent would you like your model be to your controller.
This way attributes are set for the whole life cycle except the direct initialisation and it's not interfering with derived search model.
Just override __construct() method in your model like this:
class MyModel extends \yii\db\ActiveRecord {
function __construct(array $config = [])
{
parent::__construct($config);
$this->attr = 'defaultValue';
}
...
}
If you want to load default value from database you can put this code in your model
public function init()
{
parent::init();
if(!method_exists($this,'search')) //for checking this code is on model search or not
{
$this->loadDefaultValues();
}
}
You can prepare separate method where all defaults are set and call it explicitly.
$model = new Model;
if($model->isNewRecord())
$model->setDefaultValues();

zf2 call a method from a Model in another Model

I have a couple of modules in ZF2 project. Each module has different model classes performing different required functions. Now I have method in a model class of first module which I want to call in the model class of second module. Is it possible to do so? if yes, how?
This should be fairly simple. Firstly you need to include the two modules in your application.config.php
'modules' => array(
'Module1',
'Module2'
)
Then as a very basic example taken from your question:
<?php
namespace Module2\Model;
use Module1\Model\Class1;
class Class2
{
public function doSomething()
{
$class1 = new Class1();
$class1->doSomething();
}
}

CodeIgniter - Datamapper ORM - Autopopulate Instance

Just wondering if there is an easy way to auto-populate an object’s related fields on an instance-by-instance basis rather than globally in the config file, or, for the entire class.
I’d like to include all related models for a single instance without chaining a ton of include_related() functions.
Something like this would be nice:
$x = new Model();
$x->include_all_related();
Thought I'd have to get my hands dirty in the core. For whatever reason, it didn't occur to me that I could access the $has_many and $has_one arrays.
Solution was simple:
class Model extends Datamapper{
var $has_one = array('foo', 'bar', 'baz');
var $table = 'models';
function __construct($id = NULL){
parent::__construct($id);
}
function include_all_related(){
foreach($this->has_one as $h){
$this->include_related($h['class']);
}
return $this;
}
}
You might wonder why I'm using the class key in the $h variable. Under the hood, Datamapper ORM keeps track of some other keys too as part of a bigger array. If you call print_r($h), you can see them. The class key keeps track of foo, bar and baz.
You can enable it on the relation definition, if you want is on a particular instance, you need to change the relation configuration of that instance at runtime.

Unit testing Controller method - assign value to base class property to avoid using Initialize()

This test is to check that I can return a ViewModel object by creating a customer and calling the Details() controller method.
[TestMethod()]
public void Can_View_AccountDetails()
{
AccountController target = new AccountController(null, null, null, null);
target.customer = new Customer { Id = 4, Active = true, BillingAddress_Id=1, ShippingAddress_Id=2 };
// Act
ActionResult result = target.Details();
// Assert
var resultData = ((ViewResult)result).ViewData.Model as AccountViewModel;
Assert.IsInstanceOfType(resultData, (typeof(AccountViewModel)));
}
'customer' is a member of the controller base class, which is then assigned in Initialize(). Initially I couldn't assign anything to it, but by setting it to 'public' rather than 'protected' I was able to use it in my test and avoided trying to call the base class Initialize() method.
EDIT: 'customer' is populate from a Repository object injected into the base class constructor.
Is this the right way to do this? It seems somehow wrong to change the accessibility level in order to get the test to work.
Also, although I'm trying to use Moq to create my tests, I'm not actually doing any mocking at all here which again, doesn't seem right.
I think your real problem is that the customer information "magically" shows up within the AccountController. The Customer instance should be injected into the AccountController from the outside since it is an external dependency. That being the case you would not have to make the customer property public because you pass it into the AccountController yourself.
Protected means it can only access from derived classes, so the test class would need to inherit the protected class.
Also you stubbed this as being Moq, but i don't see any Mock testing. You should be using interfaces that represent the Customer class so you can Mock the ICustomer interface.
You need to stub your Repository object and set it up so that it returns customer. Then, you don't need to expose .customer property as public (or internal) - you simply tell repository stub to return the one you'd like:
var repositoryStub = new Mock<IRepository>();
var customer = new Customer { /* ... */ };
repositoryStub.Setup(r => r.GetCustomer()).Returns(customer);
And naturally, you need to initialize your AccountContoller with stubbed dependency to repository (and other ones aswell, if needed):
var accountController = new AccountController(repositoryStub, ...);
This of course assumes your AccountController can take repository dependency.
So now, when you call Initialize() on base class, it should use stubbed repository and set your private .customer field to the one you specified it to return during stub setup.

How do you share common methods in different grails controllers?

Currently when I need to share a method like processParams(params) between different controllers, I use either inheritance or services.
Both solution has some inconvenients :
With inheritance, you cannot use multiple inheritance which means that you need to have all of your controller utility methods in one place. And also, there is a bug in grails that does not detect any code changes in Base Controller classes in development mode (you need to restart the app)
With services, you don't have access to all injected properties like params, session, flush...
So my question is : is there any other way to use some common methods accessible for multiple controllers ?
One option I like is to write the common methods as a category, then mix it into the controllers as necessary. It gives a lot more flexibility than inheritance, has access to stuff like params, and the code is simple and understandable.
Here's a tiny example:
#Category(Object)
class MyControllerCategory {
def printParams() {
println params
}
}
#Mixin(MyControllerCategory)
class SomethingController {
def create = {
printParams()
...
}
def save = {
printParams()
}
}
Common functionality is a call for a new class, not necessarily common ancestor. The question formulation is missing responsibility statement for it. Needless to say, it's a single responsibility that we create a new class for. I take further decisions basing on class responsibility.
I prefer a hybrid of robbbert's and Jared's answers: I construct extra classes, passing them necessary controller internals as parameters. Sometimes the classes develop from method objects.
Like:
def action = {
def doer = SomeResponsibilityDoer(this.request, this.response)
render doer.action()
}
Not so brief, but lets you get code under tests and keep coupling low.
As SomeResponsibilityDoer is only going to have couple of fields - request an response - it's not a big deal constructing it with every request.
It's also not a big deal having SomeResponsibilityDoer not reloaded on controller change in dev, because:
Initially, you can declare it in some of Controller files - it will be reloaded. After you complete it, hopefully it won't change often, so move it to src/groovy.
Even more important, it's faster and better for design to develop under unit tests than under application running and reloading a Contoller.
This doesn't help the restarting in development mode issue you have, but it's the way I've solved this problem. It's ugly and probably not good practice, but I factor common code into classes as closures. Then I can do something like:
new ControllerClosures().action(this)
and from with in the controllerClosures class
def action={
it.response.something
return [allYourData]
}
You can use the Delegation design pattern:
class Swimmer {
def swim() { "swimming" }
}
class Runner {
def run() { "running" }
}
class Biker {
def bike() { "biking" }
}
class Triathlete {
#Delegate Swimmer swimmer
#Delegate Runner runner
#Delegate Biker biker
}
def triathlete = new Triathlete(
swimmer: new Swimmer(),
runner: new Runner(),
biker: new Biker()
)
triathlete.swim()
triathlete.run()
triathlete.bike()
In case of a controller, assign the helper class directly at the instance field (or in the nullary constructor):
class HelperClass {
def renderFoo() { render 'foo' }
}
class FooController {
private #Delegate HelperClass helperClass = new HelperClass()
def index = { this.renderFoo() }
}
The delegate's type information gets compiled into the containing class.
You can write all the common method in commonService
and use that service to envoke commmon method

Resources