Categories: "Full Stack Dev & Design"

Testing web applications

Client Side Testing

Note to myself: unit testing is a great thing and I should do it more, I plan to do it more. But, unit testing is not enough...

What we need for web applications (or complex dynamic web sites if you prefer) would be something like this: the TEST program would act like a regular web browser, executing javascript and all the rest. The main difference with a web browser would be that the TEST program would be scriptable.

You could script it to log in, enter data into forms, perform search requests, check that the requested data appears on the screen, etc... You may even want to compare the generated HTML with a prerecorded excerpt. You may want to tolerate differences like white spaces and may be even non structural tags (ignore spans, styles attributes, etc...)

Of course, you'll want the TEST program to validate the XHTML output as well as the CSS styles.

Advanced testing would involve sending onclic events to specific objects on the page and see how the javascript behaves.

You'd have different scenarios you could run in sequence to fully test your application.

Even better: you could run multiple scenarios concurently (you'll need cookie isolated client threads for this) in order to stress load your application and record response times.

God, I gotta stop dreaming about it and find that gem...

Later:

I found a few potentially interesting tools here:

  1. Puffin Automation Framework. Open Source. [No longer exists]
  2. QEngine WebTest. Free / Commercial. [No longer exists]
  3. WAPT Web Application Testing. $ 250.
  4. WebKing. Commercial.
  5. OpenLoad. Commercial. [No longer exists]
  6. Web Performance Load Tester. 499 € +.
  7. iMacros. $30 - $499.
  8. eValid [No longer exists]

Mucho later:

Hungarian notation on steroids: semantic types & suffixes

Hungarian notation

Joel on Software’s latest bewildering article advocates correct use of the – often misunderstood – Hungarian notation: “Making Wrong Code Look Wrong“.

Basically, calling a variable unBorder because it’s an unsigned int is pointless. What’s useful is to call it xwBorder because it’s an horinzontal “x” coordinate (versus a bytecount for example) that refers to the window “w” (versus the screen or the document for example). If this doesn’t feel a 100 times better to you, go read the article now! :)

I really agree with the fact that knowning the system type of a variable when you read it is pretty much useless most of the time – especially in the age of typeless scripting languages like PHP. Knowing the semantic type of the variable is much more interesting.

As I have written before in my coding standard guidelines, there’s a situation, though, where I still like to use system types in my variable names: when I deal with Objects. For example I might use variable names like source_File and destination_File!

First, because if the Objects are properly named, then the variable names refering to them will make sense.

But there’s more: as you might have noticed, I used the object name “File” as a suffix, not as a Hungarian prefix. The reason is that if I have a method called File::rename() that I want to refactor for some reason (like merge it with File::move() ), I might need to check every place where it’s called. Actually, as I have learned from b2evolution development, these things happen all the time on larger projects…

Now, by suffixing vars with the object name, I can easily do a project wide search for File->rename( and I’ll find all calls to the method, in various contexts such as source_File>rename(), destination_File->rename(), temp_File->rename(), log_File->rename() … you get the idea…

If I have one variable misnamed as in list->rename() for example, I would not find it… unless I decide to search on just ->rename(… but I wouldn’t want that! It would get me a lot of noise like: some_Collection->rename(), some_User->rename(), some_Group->rename(), etc…

PHP Variable names, Member names, Class names

I have just extended my PHP coding standard guidelines with these rules about variable naming:

  • Remember this is PHP, not Microsoft Visual C++. There is actually little value in naming variables something like strFullTitle . Something like full_title is definitely enough and much easier to read!

  • As an exception to the previous rule, we'll preferably prefix private or protected member variables of a class with an underscore as in _full_title. This serves as an easy reminder that the variable is not designed to be called in any other ways as in $this->_full_title .
  • Class names should start with a capital, as in Book .
  • Variable names should be all lowercase, as in $title = 'A brand new day'; except when they are object references as in:

    $a_Book = & new Book( 'A brand new day' );
  • When naming object references, always end their name with the name of the class as in $a_Book or $another_Book instead of Book_to_read for example. This allows to easily search & find all calls to a given method of a given class. You could for exampel easily search on this string: "Book->get_title(" .

PNG alpha transparency in IE

Here are a few solutions to the same old IE/PNG issue, all revolving around the same hack: using JavaScript to replace IMG tags containing PNGs with a SPAN or a DIV into wich the PNG is filled using the IE proprietary AlphaImageLoader image filter.

It works... in a very disgraceful manner (try it with 200 PNG icons on the same page!)... and I don't think it degrades correctly to the ALT text display if images don't get loaded for some reason. (Not to mention CSS side effects an the rest which is usually documented along with each hack).

The illusion of DataBase Abstraction Layers or Classes

Many people think that DB abstraction is cool. I get emails about this topic all the time. People suggesting we add a DB abstraction layer to b2evolution, or offering to do so themselves.

So why haven't we added one yet? Well, simply because DB abstraction doesn't work! :!:

DB abstraction layers will mostly hide the specific interface semantics between the application and the database. Thus you don't have to worry about the specific system call to connect to each particular DB. OK nice. So what? That's only the easiest part in porting an app from a DBMS to another... (BTW, we use a class (/evocore/db.class) in b2evolution for this too. You just have to slighlty alter this class if you want to connect to another DBMS than MySQL).

More sophisticated layers will also translate between different datatypes from one DBMS to another. But since datatypes tend to standardize among all popular DBMSes this is getting less of an issue as time passes by...

Finally, we get to the point where it hurts: the SQL syntax! There are vitually no two DBMSes that share the exact same SQL syntax, except for the most basic SELECT, INSERT, UPDATE and DELETE statements! >:-[ And it doesn't seem to be standardizing really... some still won't support even the minimalistic SQL 92 standard! >:XX

Just check it out with your 2 favorite DBMSes:

  • How do you perform a LEFT OUTER JOIN?
  • How do you concatenate columns into a single result string?
  • How do you limit results in the WHERE clause to a regular expression?
  • How do you handle the fact that when you INSERT and the primary key already exists, you want to UPDATE instead? (MySQL's REPLACE INTO syntax...)?

These are just a few common examples, but they're probably already enough to show you why you DB abstraction layer won't magically translate from you first favorite DBMS to your second... You'll have to rewrite many queries too... and sometimes you won't find equivalent functionnality (subqueries?) and you'll have to write extra application code...

Not to mention triggers and stored procedures where you wouldn't even dare to dream about some kind of compatibility.

The most advanced DB abstraction I have ever worked with was ODBC. Yes that thing actually did SQL syntax translation! But it depended on specific drivers to implement translation against a standardized syntax defined by Microsoft.

So today when I see some open source library pretending to perform DB abstraction and I can't find anything closely related to SQL syntax translation, I won't even consider it... It's useless to me. The real difficulty with handling multiple DBs is rewriting the SQL queries, triggers and stored procedures... it's not connecting to yet another fancy DBMS and SELECT 'hello'... |-|