I have the following method I want to test:
class SomeObject {
public function actionFromSomeController() {
$obj = new OtherObject();
$obj -> setAttributes();
$obj -> doAction();
}
}
class OtherObject {
private $_attr;
public function setAttributes() {
$this -> _attr = 'something';
Database :: execute('INSERT INTO table VALUES (' . $this -> _attr . ')');
$fileObj = new FileObj();
$content = $fileObj -> getSomeFileContent();
// do something else
}
public function doAction() {
echo $this -> _attr;
}
}
Now I want to test this method, its output depends on database content and one file on the server. It does a lot of things on the way, and the output is just one ID and success => 1.
How should I test it properly?
Some ideas on how to test small code pieces like this:
Generate test-data and pass it to your methods (also, fake database return data or file contents)
Use echo / var_dump() / die() to check property and variable content at different positions in your methods
Also use these commands to check whether execution reaches a certain point (for example to see whether a function got called or not)
If something doesn't work as expected without an error message: Check line by line with the above methods until you find the problem
Consider using interfaces and dependency injection if your code gets bigger - this is a bit over-the-top for this amount of code, but can be a tremendous time-saver when your application becomes big
Testing is never an automatic process and you will always have to think about what makes sense to do and what not. These things to do are never magic but basic PHP.
You should consider letting your scripts throw errors/exceptions if something goes wrong. Writing "silent" applications is almost never good since you can, if you really need a silent execution for production environments, just turn off error reporting and have the same effect. Many PHP functions return something special on failure and/or success and you can check for this. Database handlers do so, too. Do yourself a favor and use these return values!
Related
I'm trying to build a static code analysis tool and I would like to check if the variables in a file are defined. Currently I'm using nikic/PHP-Parser (https://github.com/nikic/PHP-Parser), but I'm not sure if what I'm attempting is even possible.
So my question is: is it possible to check whether is (possibly) set. So does the variable contain a different value than null? Since the code is not executed in static analysis I feel like it might be impossible to "guess" whether the variable might be null, before giving it to a function for example.
An example:
$page = Expertise::find(get_the_ID());
$relatedNews = $page->connectedNews->take(-3)->reverse();
The second line might give us an exception in this case, when $page turned out to be null. I would like to detect these kinds of instabilities in the code using static analysis.
Here's a piece of code of what I'm attempting using PHP-Parser.
class NodeVisitor extends NodeVisitorAbstract
{
public function enterNode(Node $node)
{
if ($node instanceof Node\Expr\Variable) {
// is not null (is set)
// or if that's not possible: is defined before reference?
}
}
}
Edit: to be more clear on why I'm doing this, I'm trying to build an application that detects possible 500 errors without knowing anything about the execution of the code.
I apologise if this has already been answered somewhere, but I haven't managed to find an answer so far - maybe I'm searching for the wrong thing!
I am trying to figure out how to handle errors in my OO PHP system, which is used to generate web pages. Hopefully this example will explain what I mean.
Imagine I have a Content class, a Form class and a FormObject class, which hold all the information on page content, web forms and form fields. All classes can run multiple MySQL queries via the DB class.
Users can create new content or forms in the back-end. When they do this, I use the classes to create and store the data in the database.
I also have a System class, which is used to generate the web pages. The System class checks what should be displayed on the front-end, builds the appropriate Content and Form objects, then generates the HTML and outputs it to the screen.
I have some checks for serious errors, which stop the code from going any further. However, the problem is that I want to feed back some "soft errors" to the front-end. For example, maybe the System class builds a Form object, which in-turn builds the fields using the FormObject class. The FormObject class queries the database for a field name, but a field name is not found. So the DB class returns an error. I want to be able to feed back a message to the front-end that says the field name has not been found.
What is the best way to get that "soft error" message back to the System class, so it can be outputted to the front-end?
I realise it is fairly simple in this particular example, but as more classes are added and, crucially, more levels are added, the problem becomes a bit bigger.
One way I thought of doing this was to have an Error class. The system would create an Error object and pass it on to each Content and Form object as they are created. The Form class would pass the same Error object to the FormItem class. Whenever an error is found, it is logged via a method in the Error class. The system can then access the original Error object and output all the errors. However, as the system grows, more classes are added, and more objects are created, it could get quite confusing. Is there a better way?
You might want to use either
something global that all classes can access (e.g. a global variable or a Singleton), or
something that is passed in to all instantiations of classses producing what you call 'soft errors'
to collect such errors. You then want to use whatever you collected and add it to the output in your System class somehow.
To be more specific...
This is an example for the solution using a global:
global $softErrorMessages = array();
class A
{
function sampleFunctionA()
{
// [...]
// some code setting $result to some valid value
// or to false if an error occured
if($result === false) // check for validity
{
global $softErrorMessages;
$softErrorMessages[] = "The sample function A caused a soft error";
return;
}
// [...]
// some code requiring a valid $result
}
}
If you use such a global, you can then easily access it from your System class and put its contents into the right places of your output.
However, if you perform unit tests, you might not want to use globals or global-like solutions (like singletons). So here is an example for an 'error collection' approach:
class ErrorCollector
{
private $errors = array();
function addError($error)
{
$this->errors[] = $error;
}
function getErrors()
{
return $this->errors;
}
}
class A
{
private $errorCollector;
function __construct(/* your additional parameters */, ErrorCollector $errorCollector)
{
// [...]
// additional instantiation stuff
$this->errorCollector = $errorCollector;
}
function sampleFunctionA()
{
// [...]
// some code setting $result to some valid value
// or to false if an error occured
if($result === false) // check for validity
{
$this->errorCollector->addError("The sample function A caused a soft error");
return;
}
// [...]
// some code requiring a valid $result
}
}
You would instantiate the ErrorCollector only once and then pass it to all other class instantiations. Then you let your objects perform their duties (and possibly add soft errors to the ErrorCollector). Once they're done, your System class would then get all the error messages and - again - place them at the right place of your output.
Exceptions is a convenient mechanism to handle errors. FormObject can throw an exception of some SoftErrorException class if DB returns an error. And then in System you are catching this exception and render it to front-end.
class System {
public function showFormAction() {
try {
$form = ... // create a form
$this->renderForm($form);
} catch (SoftErrorException $e) {
$this->handleSoftError($e);
}
}
public function handleSoftError(SoftErrorException $e)
{
// Do whatever you want with exceptions: render it
// $this->renderErrorPage($e->getMessage());
// or collect them and show after
// $this->errors[] = $e;
}
}
I am writing fresh code, as part of refactoring an older legacy codebase.
Specifically, I am writing a Device class that will be used to compute various specifications of a device.
Device class depends on device's model number and particle count and I can call it as $device = new Device($modelNumber, $particleCount);
Problem: since this class will go into existing legacy code, I have no direct influence on if this class will be called properly. For Device to work, it needs to have correct model number and correct particle count. If it does not receive the proper configuration data, internally device will not be initialized, and the class will not work. I think that I need to find a way to let the caller know that there was an error, in case an invalid configuration data was supplied. How do I structure this to be in line with object oriented principles?
Or, alternatively, do I need to concern myself with this? I think there is a principle that if you supply garbage, you get garbage back, aka my class only needs to work properly with proper data. If improper data is supplied, it can bake a cake instead, or do nothing (and possibly fail silently). Well, I am not sure if this principle will be great. I do need something to complain if supplied configuration data is bad.
Here is some code of what I am thinking:
$device = new Device($x, $y);
$device->getData();
The above will fail or produce bad or no data if $x or $y are outside of device specs. I don't know how to handle this failure. I also want to assume that $device is valid when I call getData() method, and I can't make that assumption.
or
$device = new Device($x, $y);
if ($device->isValid())
$device->getData();
else
blow_up("invalid device configuration supplied");
The above is better, but the caller has to now they are to call isValid() function. This also "waters down" my class. It has to do two things: 1) create device, 2) verify device configuration is valid.
I can create a DeviceChecker class that deals with configuration vefication. And maybe that's a solution. It bothers me a little that DeviceChecker will have to contain some part of the logic that is already in Device class.
Questions
what problem am I trying to solve here? Am I actually trying to design an error handling system in addition to my "simple class" issue? I think I probably am... Well, I don't have the luxury of doing this at the moment (legacy code base is huge). Is there anything I can do now that is perhaps localized to the pieces of code I touch? That something is what I am looking for with this question.
I think you need to use below code to verify your passed arguments in construct
class Device {
public function __constructor($modelNumber, $particleCount) {
if(!$this->isValid($modelNumber, $particleCount) {
return false; //or return any error
}
}
}
This will check the passed params are valid or not and create object based on that only, otherwise return false or any error.
I'm working on a class-based php web app. I have some places where objects are interacting, and I have certain situations where I'm using error codes to communicate to the end user -- typically when form values are missing or invalid. These are situations where exceptions are unwarranted ( and I'm not sure I could avoid the situations with exceptions anyways).
In one object, I have some 20 code numbers, each of which correspond to a user-facing message, and a admin/developer-facing message, so both parties know what's going on. Now that I've worked over the code several times, I find that it's difficult to quickly figure out what code numbers in the series I've already used, so I accidentally create conflicting code numbers. For instance, I just did that today with 12, 13, 14 and 15.
How can I better organize this so I don't create conflicting error codes? Should I create one singleton class, errorCodes, that has a master list of all error codes for all classes, systematizing them across the whole web app? Or should each object have its own set of error codes, when appropriate, and I just keep a list in the commentary of the object, to use and update that as I go along?
Edit: So I'm liking the suggestions to use constants or named constants within the class. That gives me a single place where I programatically define and keep track of error codes and their messages.
The next question: what kind of interface do I provide to the outside world for this class' error codes and messages? Do I do something like triggerError(20) in the class, and then provide a public method to return the error code, the string constant, and the user- and admin-facing message?
You could create a couple of defines to create named constants for all your error codes :
define('ERROR_CODE_SQL_QUERY', 1);
define('ERROR_CODE_PAGE_NOT_FOUND', 2);
define('ERROR_CODE_NOT_ALLOWED', 3);
// and so on
And, then, use the constants in your code :
if ($errorCode == ERROR_CODE_SQL_QUERY) {
// deal with SQL errors
}
With that, nowhere in your code you'll use the numerical value : everywhere (except in the on and only file where you put the defines), you'll use the codes.
It means :
Less risk of errors, as all numerical values are set in only one file
Less risk of errors, as you'll use the constants, that have a name which indicates what it means
And code that's easier to read.
Another idea could be to create a class to deal with errors :
class Error {
const CODE_SQL_QUERY = 1;
const CODE_PAGE_NOT_FOUND = 2;
const CODE_NOT_ALLOWED = 3;
// Add some methods here, if needed
}
And, then, use something like this :
if ($errorCode == Error::CODE_SQL_QUERY) {
// deal with SQL errors
}
Which one is the best ?
It's probably a matter of personnal preferences... If you need to add some methods to deal with the errors, using a class might be useful. Else, defines are a great solution too.
At the very least, can you bump the code numbers up to be class constants or members?
class MyErrorProneClass {
const TURNED_INTO_A_NEWT = 12;
...
public function dontBurnMe() {
// echo your error here using self::TURNED_INTO_A_NEWT
}
This way you can manage the errors in the same place where you use them, rather than having to maintenance a large central file. I tried something to that effect in the past and it becomes difficult to keep up.
Generating error numbers programmatically may be a better long-term solution. If you could use information about the file or line number (__FILE__ and __LINE__ respectively), that would help.
Hope that moves in the right direction at least.
Thanks, Joe
Edit:
A class member would follow this syntax instead:
class MyErrorProneClass {
protected static $turnedIntoANewt = 12;
...
public function dontBurnMe() {
// echo your error here using self::$turnedIntoANewt
}
Since constants are public by default, you can access them from other classes directly if you want. So, from the outside, the error would be referenced as:
MyErrorProneClass::TURNED_INTO_A_NEWT
For associating to messages, you would use a mapping (either in a database, or in some localization file) from error ID (and frontend/backend) to displayed string. This use of keys for messages isn't optimal, but it would allow you to change error messages without changing code as well.
If you don't know already it might be an idea to use trigger_error (), plus an error handler if you want to present the user with a better error message.
Have you thought about using exceptions? They may be a good choice for your problem here although adding them to your project now would probably require some restructuring.
You can extend the basic exception class so it fits your problem in terms the of user / developer error message separation.
How should I write error reporting modules in PHP?
Say, I want to write a function in PHP: 'bool isDuplicateEmail($email)'.
In that function, I want to check if the $email is already present in the database.
It will return 'true', if exists. Else 'false'.
Now, the query execution can also fail, In that time I want to report 'Internal Error' to the user.
The function should not die with typical mysql error: die(mysql_error(). My web app has two interfaces: browser and email(You can perform certain actions by sending an email).
In both cases it should report error in good aesthetic.
Do I really have to use exception handling for this?
Can anyone point me to some good PHP project where I can learn how to design robust PHP web-app?
In my PHP projects, I have tried several different tacts. I've come to the following solution which seems to work well for me:
First, any major PHP application I write has some sort of central singleton that manages application-level data and behaviors. The "Application" object. I mention that here because I use this object to collect generated feedback from every other module. The rendering module can query the application object for the feedback it deems should be displayed to the user.
On a lower-level, every class is derived from some base class that contains error management methods. For example an "AddError(code,string,global)" and "GetErrors()" and "ClearErrors". The "AddError" method does two things: stores a local copy of that error in an instance-specific array for that object and (optionally) notifies the application object of this error ("global" is a boolean) which then stores that error for future use in rendering.
So now here's how it works in practice:
Note that 'Object' defines the following methods: AddError ClearErrors GetErrorCodes GetErrorsAsStrings GetErrorCount and maybe HasError for convenience
// $GLOBALS['app'] = new Application();
class MyObject extends Object
{
/**
* #return bool Returns false if failed
*/
public function DoThing()
{
$this->ClearErrors();
if ([something succeeded])
{
return true;
}
else
{
$this->AddError(ERR_OP_FAILED,"Thing could not be done");
return false;
}
}
}
$ob = new MyObject();
if ($ob->DoThing())
{
echo 'Success.';
}
else
{
// Right now, i may not really care *why* it didn't work (the user
// may want to know about the problem, though (see below).
$ob->TrySomethingElse();
}
// ...LATER ON IN THE RENDERING MODULE
echo implode('<br/>',$GLOBALS['app']->GetErrorsAsStrings());
The reason I like this is because:
I hate exceptions because I personally believe they make code more convoluted that it needs to be
Sometimes you just need to know that a function succeeded or failed and not exactly what went wrong
A lot of times you don't need a specific error code but you need a specific error string and you don't want to create an error code for every single possible error condition. Sometimes you really just want to use an "opfailed" code but go into some detail for the user's sake in the string itself. This allows for that flexibility
Having two error collection locations (the local level for use by the calling algorithm and global level for use by rendering modules for telling the user about them) has really worked for me to give each functional area exactly what it needs to get things done.
Using MVC, i always use some sort of default error/exception handler, where actions with exceptions (and no own error-/exceptionhandling) will be caught.
There you could decide to answer via email or browser-response, and it will always have the same look :)
I'd use a framework like Zend Framework that has a thorough exception handling mechanism built all through it.
Look into exception handling and error handling in the php manual. Also read the comments at the bottom, very useful.
There's aslo a method explained in those page how to convert PHP errors into exceptions, so you only deal with exceptions (for the most part).