What would be the correct way of unit testing a controller action that performs a redirect?
UPDATE: I'm a core developer on the CFWheels project. The whole reason I'm asking this question is currently I'm working on enhancing the built in testing framework we have and I'm wondering on how to approach and implement something like this in CFWheels to make it easier for developers to test their application.
UPDATE: I figured out how to test this. it seems that we will have to rewrite the wheels controller internals a bit to perform the redirect after the action completes and after it gets passed back to the dispatcher. the only thing with this approach is that any code after the redirectTo() would be ran EXCEPT if you take the appropriate precautions before hand; this includes either putting a return after the redirectTo() statement or putting conditional checks in your action to isolate the redirectTo() code from other code. It also involves making sure that nothing else is rendered once a redirectTo() is performed.
Stuff like this becomes a whole lot easier to test if you break apart the redirect mechanism into multiple functions: a) a function that determines the target URL and b) a function that performs the redirect.
This way, you can test functionA very easily, and functionA is the one you want to test anyway. It's the code you wrote. It's where your real logic is. FunctionB is not your code; it's ColdFusion guts, and there's not much sense in testing CFLocation.
If you're on some mission to achieve 100% test coverage, then you could spend 10 tests for functionA where you exercise all the different branches of your logic, and then one test for functionB which exercises the redirect in the manner that Terry suggests; so in this manner, you only get 1 slow test instead of 10.
You can generalize this approach for uses in other scenarios: file systems, webservices, http, ftp, email, etc: "Extract the stuff you can control and want to test from the stuff you can't control and don't want to test"
You could call the controller with the appropriate URL using cfhttp with redirect set to false. Then test the resulting cfhttp result struct, it should have info about where the redirect would take you.
Related
I want to test the return of a script that queries a list of urls (more than 1000), extracts some data from the response and returns it as an array of objects (dict) with certain attributes.
Is it safe to test only a sample from the returned list ?
My concern is mainly that exhaustive testing would be time consuming.
P.S. I am hoping that a random sampling would help catch errors, knowing that the response bodies of the urls my script queries may be inconsistant.
Thanks,
I understand your question such that you actually access the urls in the list. In unit-testing, you would normally take a different approach (but not in integration-testing, see the bottom of my answer). You would not actually access those urls, but instead find some way to "simulate" the url access. As part of this simulated url access, your tests can also define what the responses look like.
This way, you can test all aspects of your code that handles the responses. You can simulate all kinds of valid, but also as you mention inconsistent responses - because you have full control from the tests.
There are several ways to make it possible for your tests to "simulate" that url access: One option is, to separate within your code the part that does the url access from the part that processes the response. In pseudo-code:
response = accessUrl(url);
handleResponse(response);
Then, in unit-testing you would focus on testing the function handleResponse, and test the rest of the code in integration-testing.
A second option is to mock the function/method that performs the url access. This makes sense if it is difficult to change the code to achieve the separation I have shown in the pseudo-code. There are lots of information about mocking available on the web.
In any case, this way of testing allows you to test the functionality of your code more systematically. You can test all scenarios you are aware of and will be sure that these were really covered because you have full control.
The testing approach you have described is more on the level of integration testing, and also makes sense after you have fully unit-tested your code: Because, after all, you may still have missed some real-world scenarios that your code should handle.
I have a web application which currently exists as a single large class containing a front controller, and a bootstrap file which runs the class and passes in the settings.
Over time, the class has become over-large, with multiple concerns, that I have long wanted to refactor into what will be rather obvious subclasses. I'm very familiar with all kinds of refactorings.
However, for this application, at present there is no test coverage. Because all interactions are done by reading GET and POST parameters, there is only one public method into the system, i.e. such URL interactions through the front controller entry point. So the class is hard to unit test (I will be using PHPUnit) as it stands.
Obviously it is far safer to refactor with tests already in place. So I would welcome views on which strategy is best:
1) Create a pile of tests that implement GET and POST interactions as per a user using the web application; or
2) Create a pile of tests against the private functions by using the ReflectionClass workaround, and convert these to standard PHPUnit tests concurrently with the refactoring; or
3) Add unit testing after doing the subclass refactoring, testing the public entry API points to the new subclasses.
Either way how you approach it, I would do it one-functionality at a time if you can, it makes the task less daunting and therefore more achievable...
When confronted with such situations in the past (quite a few times in fact), I usually do this:
First of all, does the application use external dependencies like databases? The first thing is that we need to make these predictable. I usually try to find where the creation of these external dependencies occur and then delegate it to a good Dependency Injection framework (like Pimple).
Once that is done you can add rules to the DI factory methods that return test databases depending on some conditions set: I usually use a test domain for this, so if the site is foo.local then i also have a domain test.foo.local that sets (in the Apache config for example) an environment variable APPLICATION_ENV set to 'tests'. The DI container can then inspect this environment variable to serve the right dependency, in our case a connection pointing to a test database.
(It don't like that production code is aware of that it might be in a test scenario, but it's a lesser evil, and it can be alleviated by using config files that have the environment variable in the filename for example. I digress.)
When this is done, in my tests I then have a reference to the same test database which I then use to set up some predictable test data with some thing like DbUnit or test-db-acle (disclaimer, I wrote the latter one, so I tend towards that).
Once the test data is in place, I issue a request to the url in question with something like Guzzle (in various important variations) and record the output(s), which I then use to make a test that sets the behaviour 'in stone'.
NOTE: this is a very imprecise method, the best way for tests is in a test-driven way, but this is not a solution in this case obviously.
However, if you are reasonable sure that some manual testing has been done on this, then this is a good way to at least get a few smoke tests into place. In my experience the value of having even one rudimentary smoke test in place is infinitely more valuable than not having any.
Now that you have a smoke test in place, you can refactor this part of the application and move to a new one.
I hope this help....
I am new to unit testing. Suppose I am building a web application. How do I know what to test? All the examples that you see are some sort of basic sum function that really has no real value, or at least I've never written a function to add to inputs and then return!
So, my question...on a web application, what are the sort of things that need tested?
I know that this is a broad question but anything will be helpful. I would be interested in links or anything that gives real life examples as opposed to concept examples that don't have any real life usage.
Take a look at your code, especially the bits where you have complex logic with loops, conditionals, etc, and ask yourself: How do I know if this works?
If you need to change the complex logic to take into account other corner cases then how do you know that the changes you introduce don't break the existing cases? This is precisely what unit testing is intended to address.
So, to answer your question about how it applies to web applications: suppose you have some code that lays out the page differently depending on the browser. One of your customers refuses to upgrade from IE6 and insists that you support that. So you unit test your layout code by simulating the connection string from IE6 and checking that the layout is what you expect.
A customer tells you they've found a security hole where using a particular cookie will give you administrator access. How do you know that you've fixed the bug and it doesn't happen again? Create a unit test for it, and run the unit tests on a daily basis so that you get an early warning if it fails.
You discover a bug where users with accents in their names get corrupted in the database. Abstract out the webform input from the database layer and add unit tests to ensure that (eg) UTF8 encoded data is stored in the database correctly and can be retrieved.
You get the idea. Anywhere where part of the process has a well-defined input and output is ideal for unit testing. Anything that doesn't is ideal for refactoring until it is well defined. Take a look at projects such as WebUnit, HTMLUnit, XMLUnit, CSSUnit.
The first part of testing is to write testable applications. Separate out as much functionality as possible from the UI. Refactor into smaller methods. Learn about dependency injection, and try using that to create methods that can take simple, throw-away input that produces known (and therefor testable) results. Look at mocking tools.
Infrastructure and data layer code is easiest to test.
Look at behavior-driven testing as well as test-driven design. For my money, behavior testing is better than pure unit testing; you can follow use-cases, so that tests match against expected usage patterns.
Unit testing means testing any unit of work, the smallest units of work are methods and functions., The art of unit testing is to define tests for a function that cannot just be checked by inspection, what unit test aims at is to test every possible functional requirement of a method.
Consider for example you have a login function, then there could be following tests that you could write for failures:
1. Does the function fail on empty username and password
2. Does the function fail on the correct username but the wrong password
3. Does the function fail on the correct password but the wrong username
The you would also write tests that the function would pass:
1. Does the function pass on correct username and password
This is just a basic example but this is what unit testing attempts to achieve, testing out things that may have been overlooked during development.
Then there is a purist approach too where a developer is first supposed to write tests and then the code to pass those tests (aka test driven development).
Resources:
http://devzone.zend.com/article/2772
http://www.ibm.com/developerworks/library/j-mocktest.html
If you're new to TDD, may I suggest a quick trip into the world of BDD? My experience is that the language really helps people pick up TDD more quickly. Particularly, I point you at this article, in which Dan North suggests "what to test":
http://blog.dannorth.net/introducing-bdd/
Note for transparency: I may be heavily involved in the BDD movement.
Regarding the classes to unit test in a web-app, I'd consider starting with controllers, domain objects if they have complex behaviour, and anything called "service", "manager", "helper" or "util". Please also try renaming any classes like this so that they are less generic and actually say what they do. Classes called "calculator" or "converter" are also good candidates, and you'll probably find more in the same package / folder.
There are a couple of good books which could help you too:
Martin Fowler, "Refactoring"
Michael Feathers, "Working Effectively with Legacy Code"
Good luck!
If you start out saying, "How do I test my web app?" that is biting off a lot at once, and it's going to be hard to see unit testing as providing any kind of benefit. I got into unit testing by starting with small pieces that were isolated, then writing libraries test-first, and only then building whole applications that were testable.
Generally a web app has a domain model, it has data access objects that do queries on a database and return domain objects, it has services that call the data access objects, and it has controllers that accept http requests and call the services.
Tests for the controllers will check that they call the right service method with the right parameters. Service objects can be mocks injected during test setup.
Tests for the services will check that they call the right data access objects and perform whatever logic they need to be performing. Data access objects can be mocks injected during test setup.
Tests for the data access objects will check that they perform the right database operation (query or update or whatever) by checking the contents of the database before and after. For dao tests you'll need a database, and a tool like DBUnit to pre-populate it before the test. Also your domain objects' getters and setters will get exercised with this test so you won't need a separate test for them.
Tests for the domain model will check that whatever domain logic you have encoded in them works (Sometimes you may not have any). If you design your domain model so it is not coupled to the database then the more logic you put in the domain model the better because it's easy to test. You shouldn't need any mocks for these tests.
For a web app the kind of tests you need to do are slightly different. Unit tests are tests which test a particular component of your program. For a web app, you would need to test that forms accept/reject the right inputs, that all links point to the right place, that it can cope with unexpected inputs etc. I'd have a look at Selenium if I were you, I've used it extensively in testing a number of sites: Selenium HQ
I don't have experience of testing web apps, but speaking generally: you unit test the smallest 'chunks' of your program possible. That means you test each function on an individual basis. Anything on a larger scale becomes an integration test.
Of course, there are going to be methods so simple that its not worth your time to write a test for them, but on the whole aim to test as great a proportion of your code as possible.
A rule of thumb is that if it is not worth testing it is not worth writing.
However, some things are very difficult to test, so you have the do some cost benefit analysis on what you test. If you initially aim for 70% code coverage, you will be on the right track.
I'm writing an upload function for ColdFusion of Wheels and need to unit test it once it's finished. The problem I'm having though is that I have no idea on how to create a mock multi-part form post in ColdFusion that I can use in my unit tests.
What I would like to be able to do is create the mock request simulating a file being uploaded that cffile could then process and I could check against.
I saw in the online ColdFusion help, an example of creating such a request using cfhttp, however it has to post to another page which kind of defeats that whole purpose.
Great question rip. For what it's worth, I contribute to MXUnit (wrote the eclipse plugin) and this scenario came up in a presentation I did at cfobjective this year on writing easier-to-test code (http://mxunit.org/doc/zip/marc_esher_cfobjective_2009_designing_for_easy_testability.zip).
In this scenario, I'd suggest NOT testing the upload. I believe we shouldn't spend time testing stuff that's not our code. The likelihood that we'll catch a bug or other oddity is sufficiently low for me to justify leaving it untested. I believe we should be testing "our" code, however.
In your scenario, you have two behaviors: 1) the upload and 2) the post-upload behavior. I'd test the post-upload behavior.
This now frees your unit test to not care about the source of the file. Notice how this actually results in a decoupling of the upload logic from the "what do I do with the file?" logic. Taken to its conclusion, this at least creates the potential (theoretically) to reuse this post-upload logic for stuff other than just uploads.
This keeps your test much easier, because now you can just test against some file that you put somewhere in the setUp of the unit test itself.
So your component changes from
<cfffunction name="uploadAndDoStuff">
to
<cffunction name="upload">
and then
<cffunction name="handleUpload">
or "handleFile" or "doSomethingWithFile" or "processNetworkFile" or some other thing. and in your unit test, you leave upload() untested and just test your post-upload handler. For example, if I were doing this at work, and my requirements were: "Upload file; move file to queue for virus scanning; create thumbnails if image or jpg; add stuff to database; etc" then I'd keep each of those steps as separate functions, and I'd test them in isolation, because I know that "upload file" already works since it's worked since CF1.0 (or whatever). Make sense?
Better yet, leave the "upload" out of the component entirely. nothing wrong with keeping it in a CFM file since there's kind of not much point (as far as I can see) in attempting to genericize it. there might be benefits where mocking is concerned, but that's a different topic altogether.
I did a quick search for MXUnit testing a form upload and came up with this google groups thread : Testing a file upload
Its a discussion between Peter Bell and Bob Silverberg - the outcome of which is that testing a file upload is actually part of acceptance testing as opposed to a unit test.
I know that doesn't strictly answer your question, but I hope it helps.
Strictly speaking you are right. If you have to go out to make a call to an external resource do test something ( database, web service, file uploader) it does defeat the purpose of unit testing. The best general advice is to mock out behaviours of external resources and assume they function or are covered by their own unit tests.
Pragmatism can alter this though, on the Model-Glue framework codebase, we have a number of unit tests that call out to external resources, like for persisting values across a redirect, connecting the AbstractRemotingService functionality and so on. These were deemed important enough features to unit test and we chose to make external dependencies of our unit tests to ensure good coverage. After all, in framework code, there IS NOT acceptance tests. Those are done by our users and users of a framework expect flawless code, as they should.
So there are cases where you want to test a vital external resource and you want it handled by an automated function, it can make sense to add it to your unit tests. Just know you are deviating away from a best practice that is there for a reason.
Dan Wilson
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();
}
}
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.
The reason this function is more difficult to unit test is because the database update is a side-effect of the function (i.e. there is no explicit return for you to test).
One way of dealing with state updates on remote objects like this is to create a mock object that provides the same interface as the DB (i.e. it looks identical from the perspective of your code). Then in your test you can check the state changes within this mock object and confirm you have received what you should.
You can break it down some more, that function is doing alot which makes testing it a bit tricky, not impossible but tricky. If on the other hand you pulled out some smaller extra functions (getUserByUsername, deletePasswordByUserID, addPasswordByUserId, etc. Then you can test those easily enough once and know they work so you don't have to test them again. This way you test the lower down calls making sure they are sound so you don't have to worry about them further up the chain. Then for this function all you need to do is throw it a user that does not exist and make sure it comes back with a USER_DOESNT_EXIST error then one where a user does exist (this is where you test DB comes in). The inner works have already been exercised else where (hopefully).
Unit tests serve the purpose of verifying that a unit works. If you care to know whether a unit works or not, write a test. It's that simple. Choosing to write a unit test or not shouldn't be based on some chart or rule of thumb. As a professional it's your responsibility to deliver working code, and you can't know if it's working or not unless you test it.
Now, that doesn't mean you write a test for each and every line of code. Nor does it necessarily mean you write a unit test for every single function. Deciding to test or not test a particular unit of work boils down to risk. How willing are you to risk that your piece of untested code gets deployed?
If you're asking yourself "how do I know if this functionality works", the answer is "you don't, until you have repeatable tests that prove it works".
In general one might "mock" the object you are invoking, verifying that it receives the expected requests.
In this case I'm not sure how helpful that is, you amost end up writing the same logic twice ... we thought we sent "DELETE from password" etc. Oh look we did!
Hmmm, what did we actually check. If the string was badly formed, we woudln't know!
It may be against the letter of Unit testing law, but I would instead test these side-effects by doing separate queries against the database.
Testing the public interface is necessary, but not sufficient. There are many philosophies on how much testing is required, and I can only give my own opinion. Test everything. Literally. You should have a test that verifies that each line of code has been exercised by the test suite. (I only say 'each line' because I'm thinking of C and gcov, and gcov provides line-level granularity. If you have a tool that has finer resolution, use it.) If you can add a chunk of code to your code base without adding a test, the test suite should fail.
Databases are global variables. Global variables are public interfaces for every unit that uses them. Your test cases must therefore vary inputs not only on the function parameter, but also the database inputs.
If your unit tests have side-effects (like changing a database) then they have become integration tests. There is nothing wrong in itself with integration tests; any automated testing is good for the quality of your product. But integration tests have a higher maintenance cost because they are more complex and are easier to break.
The trick is therefore to minimize the code that can only be tested with side effects. Isolate and hide the SQL queries in a separate MyDatabase class which does not contain any business logic. Pass an instance of this object to your business logic code.
Then when you unit test your business logic, you can substitute the MyDatabase object with a mock instance which is not connected to a real database, and which can be used to verify that your business logic code uses the database correctly.
See the documentation of SimpleTest (a php mocking framework) for an example.