How far should I go with unit testing?
unit-testing
Solution
The great thing about unit testing, for me at least, is that it shows you where you need to refactor. Using your sample code above, you've basically got four things happening in one method:
//1. get the user from the DB
//2. in a big else, check if user is null
//3. create a array containing the userID, a code, and expiry
//4. delete any existing password resets
//5. create a new password reset
Unit testing is also great because it helps highlight dependencies. This method, as shown above, is dependent on a DB, rather than an object that implements an interface. This method interacts with systems outside its scope, and really could only be tested with an integration test, rather than a unit test. Unit tests are for ensuring the working/correctness of a unit of work.
Consider the Single Responsibility Principle: "Do one thing". It applies to methods as well as classes.
I'd suggest that your `generatePasswordReset` method should be refactored to:
- be given a pre-defined existing user object/id. Do all those sanity checks outside of this method. Do one thing.
- put the password reset code into its own method. That would be a single unit of work that could be tested independently of the `SELECT`, `DELETE` and `INSERT`.
- Make a new method that could be called `OverwriteExistingPwdChangeRequests()` which would take care of the DELETE + INSERT.
Problem
I'm trying to unit test in a personal PHP project like a good little programmer, and I'd like to do it correctly. From what I hear what you're supposed to test is just the public interface of a method, but I was wondering if that would still apply to below. I have a method that generates a password reset token in the event that a user forgets his or her password. The method returns one of two things: nothing (null) if everything worked fine, or an error code signifying that the user with the specified username doesn't exist. If I'm only testing the public interface, how can I be sure that the password reset token IS going in the database if the username is valid, and ISN'T going in the database if the username is NOT valid? Should I do queries in my tests to validate this? Or should I just kind of assume that my logic is sound? Now this method is very simple and this isn't that big of a deal - the problem is that this same situation applies to many other methods. What do you do in database centric unit tests? Code, for reference if needed: ``` public function generatePasswordReset($username) { $this->sql='SELECT id FROM users WHERE username = :username'; $this->addParam(':username', $username); $user=$this->query()->fetch(); if (!$user) return self::$E_USER_DOESNT_EXIST; else { $code=md5(uniqid()); $this->addParams(array(':uid' => $user['id'], ':code' => $code, ':duration' => 24 //in hours, how long reset is valid )); //generate new code, delete old one if present $this->sql ='DELETE FROM password_resets WHERE user_id=:uid;'; $this->sql.="INSERT INTO password_resets (user_id, code, expires) VALUES (:uid, :code, now() + interval ':duration hours')"; $this->execute(); } } ```