Having never written any automated tests, how should I start behaviour-driven development?

It looks like the main question you're asking is, "how do I write testable code"?

Being a fan of object oriented programming I know I'm biased, but in my experience it's far easier to test code that is written in an OO style. The reason for this is that unit tests are meant to test small, isolated components of a system, and well designed object oriented code (mostly) provides this.

I agree that functions are often linked to the context that they're in, making them difficult to test. I don't have a lot of experience with functional programming, but I know that context is often passed around in some sort of variable, making it difficult to separate concerns of functions.

With OO programming, I have successfully tested objects that wrap around HTTP requests, database queries, etc, by mocking the object that does the actual network request to return a known set of data. You then test that your wrapper object handles that data in the right way. You can also test for failures and unexpected data. Another way of doing this is by setting up a local server that you use instead of the normal endpoint, but this gives your test suite an external dependency, which should be avoided when possible.

When testing HTML, many people don't do this at all, due to the highly changeable nature of the view layer. However, there are some things that are really worth testing, but never the full string of HTML - as you've discovered, just a tiny change would mean that the whole test breaks. What are you really testing in that case, that two strings in separate parts of your code base are the same?

The best thing to do is the load the HTML string from your function/object into an HTML parser library, and you can normally use Xpath or CSS selectors to check for tags with particular classes, IDs or other attributes, and check the number of elements that match certain requirements. Rspec has this built in (the have_tag() method), as do many testing libraries.

Something else you might like to look at is integration testing (e.g. Capybara, Selenium). This will load your web app with a JavaScript engine, so you can check for HTML elements and also JavaScript events.

On the whole mocking/stubbing thing, you generally only want to do this with objects that are dependencies of the object you're testing. Otherwise you can pretty much manipulate anything to assert as true!

As for resources on testing, I'd recommend looking at test driven development books even if you don't plan to practice TDD. The main reason is that they throw you head first into testing. here are a few:

  1. Kent Beck's book Test Driven Development: By Example
  2. Free ebook on TDD with PHP, Practical PHP Testing
  3. This website, Art of Unit Testing
  4. Slideshare - just search for unit testing or BDD and read as many as possible!
  5. David Chelimsky et. al.: The RSpec Book