I'm very new to TDD world. I have a few questions regarding TDD.
Do I have to do test-first in TDD? I heard that TDD is not about test. It's about design. I'm agreed that it's good to do test-first but what I like to know is that is it still TDD if we follow the test-last approach?
Shall we prefer to use BDD over TDD? I used to list out the specification of my task first and I try to write the test case based on my specification. Is it wrong approach? Do you guys prefer using BDD or TDD for your development?
Mocking? Some people from my team used to say that they are praticsing TDD. But they never follow test-first approach. they never mock the data. Do we have to mock the data in TDD?
"Using Mock Library" Vs "creating the mock class with data manually". Do you prefer to use mock library or create the mock classes with some mock data?
Any recommended book for TDD or BDD? I read Kent Beck's classic Test-Driven Development - By Example. I found that this book is published in very early stage of TDD so some of the things in this book are not a bit outdated.
1). Do I have to do test-first in TDD?
I heard that TDD is not about test.
It's about design. I'm agreed that
it's good to do test-first but what I
like to know is that is it still TDD
if we follow the test-last approach?
Yes! Strictly speaking TDD is Test-Driven Development. So the development is driven by the test. So you test first, then develop program to pass all tests.
2). Shall we prefer to use BDD over
TDD? I used to list out the
specification of my task first and I
try to write the test case based on my
specification. Is it wrong approach?
Do you guys prefer using BDD or TDD
for your development?
I think you should balance them. Use other technique to provide overall design first as best as time provide (do risk management to find appropriate time you should spend on designing) (Find a paper about "RUP essential". It give quite a good idea about balancing agile and less-agile). Identify the most critical parts then creates test and develop to pass the test.
3).Mocking? Some people from my team
used to say that they are praticsing
TDD. But they never follow test-first
approach. they never mock the data. Do
we have to mock the data in TDD?
Test-first and mocking is not the same thing. Mocking allows code to be more testable as well as be testable when other part (which this code relies on) does not exist. So if there is no such dependency (IF!!), then you can to not mock them. (Read "Working Effectively with Legacy Code" about Seam point for more details).
4). "Using Mock Library" Vs "creating the mock class with data manually". Do
you prefer to use mock library or
create the mock classes with some mock
data?
I think it just like using someone-else library or create yourown. Totally depends on the situation and many factors. For example, if you project is big and you can find appropriate mock library, use it.
5). Any recommended book for TDD or BDD? I read Kent Beck's classic
Test-Driven Development - By Example.
I found that this book is published in
very early stage of TDD so some of the
things in this book are not a bit
outdated.
There are list of books on TDD here.
Hope this helps.
Yes, it is about design, but this design methodology does involve writing tests first. People follow this rule with varying degrees of strictness, but most people I know who practice TDD tend to believe that it's better to follow the rule.
BDD has been described as TDD done right. The difference is minimal. Essentially BDD just makes the point about tests as specifications more explicit.
There is a great deal of disagreement about the usefulness of mocks. I personally prefer to test interfaces, and I avoid placing expectations in a mock. That said, testing in isolation is still a good idea for a wide variety of reasons, not the least of which is test speed. There's nothing more annoying than refactoring a piece of code which still conforms exactly to the previous interface, having a fully-working end result, and yet all the tests fail because the expectations on the mock weren't met anymore. Bad mock usage results in testing of implementation details rather than ensuring that the work performed is correct.
See #3. I prefer to just use a stub with no expectations or alternatively an integration test.
Test-Driven Development: A Practical Guide by Dave Astels. Highly recommended.
Do I have to do test-first in TDD?
Yes, TDD is, in essence:
vagueness -> bullet points -> tests -> code
If you are using some other process, it can make sense to use some of the tools and techniques, but it won't really be TDD. For whatever that is worth.
Mocking?
There are 4 more or less viable alternatives which different gurus will advocate.
mock-to-zero: mock every dependency such that every unit (e.g. java class) is effectively isolation tested.
mock-to-linear: mock cyclic dependencies only, such that there is a linear ordering of tests whereby each unit is tested only with tested dependencies.
mock-for-speed: only mock slow, asynchronous or otherwise problematic interfaces.
zero-mocking: just test stuff, use a debugger to work out what's going on if things break.
Avoid #1 if you don't love your mocking tool, and avoid #4 if you don't love your debugger.
For BDD you can find a great reference in :
The Cucumber Book: Behaviour-Driven Development for Testers and Developers (Pragmatic Programmers)
Specification by example a book by Gojko Adzic
The Secret Ninja Cucumber Scrolls
You can also follow the work of Dan North for him the difference between TDD and BDD is small
Other link Learning Behavior Driven Development (BDD)
For my self I think if you do BDD you already do TDD
I hope this helps
Yes testing first is pretty much what TDD is.
If you have no experience with either, I would start with TDD to get your feet wet (my opinion).
You don't HAVE to mock to do TDD. However, if your application has classes which depend on other classes (which is pretty much guaranteed) you should come across mocking. BTW mocking is not about mocking the data, but mocking the interaction between the class you are testing and its collaborators, the other class(es) it is dependent upon.
Mocking by hand is a good way to understand it but mocking / isolation frameworks is the way to go if you don't want to spend your whole time writing fake implementations.
IMO, Beck's book is a timeless classic and a great way to start. If you work with .NET, I just read The Art of Unit Testing which covers in great detail good techniques and practices when unit testing.
(I picked the easiest question to answer as I am not qualified to answer other questions )
Any recommended book for TDD or BDD?
Agile Software Development, Principles, Patterns, and Practices , by Robert C. Martin
Extreme Programming Explained ,by Kent Beck
Do I have to do test-first in TDD?
Yes, TDD is necessarily test-first. Writing the test first allows to think about the function to be written in terms of behavior, rather than of implementation, focusing on invoking the function and verifying the result.
This leads to testable code ; otherwise you may find yourself in a dead end.
Writing tests first also make it easier not to forget or neglect tests.
Moreover, writing - and failing - the tests first allows testing the test. A test written after the code might never fail.
Shall we prefer to use BDD over TDD?
Some say BDD is TDD done right as the focus is put on specifications.
Do we have to mock the data in TDD?
Some people from my team used to say
that they are praticsing TDD. But they
never follow test-first approach.
You don't have to use mock objects. There are just a tool, that can be convenient sometimes.
"Using Mock Library" Vs "creating the
mock class with data manually".
I never felt the need to resort to a mock object generator.
Any recommended book for TDD or BDD?
TDD by example, is a very good tutorial and presents a bunch of patterns. Another great book, more a reference is xUnit patterns.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I have a good grasp of unit testing, DI, mocks, and all the design principal goodness required to have as close to full code coverage as humanly possible (single responsibility principal, think 'how will i test this' as I code, etc...).
My most recent app, I did not code doing true TDD. I kept unit-testing in mind as I coded, and wrote my tests after writing the code, refactoring, etc.. I did TDD when it was 'easy' to do... however I did not have as good of a grasp as I do now... That was the first project I made full use of DI, mocking frameworks, etc, and the first which had full code coverage - and I learned a lot from it as I went along. I'm itching to get assigned to my next project so I can code it completely doing TDD from scratch.
I know this is a broad question, and I've already ordered TDD by example and XP Unleashed, but I'm hoping for a brief overview of how you all design / write a large application doing TDD.
Do you write the entire application, using nothing but stubbed out code? (e.g., write all the function signatures, interfaces, structures, and write the entire application but without writing any actual implementation)? I could picture it working on small-mid sized, but is this even possible on large applications?
If not, how the heck would you write your first unit test for the highest level function in your system? Lets say for example - on a web service where you have a function called DoSomethingComplicated(param1,...,param6) exposed to the world. Obviously, writing the test first for a simple function like AddNumbers() is trivial - but when the function is at the top of the call stack such as this?
Do you still do design up-front? Obviously you still want to do 'architecture' design - e.g., a flow chart showing IE talking to IIS which talks to a windows service via WCF which talks to the SQL Database... an ERD which shows all your SQL tables and their fields, etc... but what about class design? Interactions between the classes, etc? Do you design this up-front, or just keep writing stub code, refactoring the interactions as you go along, until the whole thing connects and looks like it will work?
Any advice is much appreciated
Do you do design up front?
Of course you do. You've got a big application in front of you. You've got to have some idea of the structure it will have before you start writing tests and code. You don't have to have it all worked out in detail, but you should have some basic idea of the layers, components, and interfaces. For example, if you are working on a web services system, you ought to know what the top level services are, and have a good first approximation of their signatures.
Do you write the entire application using nothing but stubbed out code?
No. You stub things out only if they are really difficult to control in a test. For example, I like to stub out the database, and the UI. I will also stub out third party interfaces. Sometimes I will stub out one of my own components if it vastly increases the test time, or it forces me to create test data that is too complicated. But most of the time I let my tests work on a pretty well integrated system.
I have to say I really dislike the style of testing that relies heavily on mocks and stubs. Don't get me wrong, I think mocks and stubs are very useful for decoupling from things that are hard to test. But I don't like writing things that are hard to test, and so I don't use a lot of mocks and stubs.
How do you write your first unit test for a high level function?
Most high level functions have degenerate behavior. For example, login is a pretty high level function and can be very complicated. But if you try to log in with no user name and no password, the response from the system is going to be pretty simple. Writing that tests will also be very simple. So you start with the degenerate cases. Once you have exhausted them, you move on to the next level of complexity. For example, what if a user tries to log in with a username but no password? Bit by bit you climb the ladder of complexity, never tackling the more complex aspects until the less complex aspects are all passing.
It is remarkable how well this strategy works. You might think that you'd just be climbing around the edges all the time and never getting to the meat; but that's not what happens. Instead you find yourself designing the internal structure of the code based on all the degenerate and exceptional cases. When you finally get around to the primary flow, you find that the structure of the code you are working on has a nice hole of just the right shape to plug the main flow in.
Please don't create your UI first.
UIs are misleading things. They make you focus on the wrong aspects of the system. Instead, imagine that your system must have many different UIs. Some will be web, some will be thick client, some will be pure text. Design your system to work properly irrespective of the UI. Get all the business rules working first, with all tests passing. Then plug the UI in later. I know this flies in the face of a lot of conventional wisdom, but I wouldn't do it any other way.
Please don't design the database first.
Databases are details. Save the details for later. Rather, design your system as though you had no idea what kind of database you were using, Keep any notion of schema, tables, rows, and columns out of the core of the system. Implement your business rules as though all the data were kept in memory all the time. Then add the database later, once you've gotten all the business rules working. Again, I know this flies in the face of some conventional wisdom, but coupling systems to databases too early is a source of a lot of badly warped designs.
Do I write the entire application, using nothing but stubbed out code?
No, not in the slightest sense - that sounds like a very wasteful approach. We must always keep in mind that the underlying reason for doing TDD is rapid feedback. An automated test suite can tell us if we broke anything much faster than a manual test can. If we wait wiring things together until the last moment, we don't get rapid feedback - while we may get rapid feedback from our unit tests, we wouldn't know if the application works as a whole. Unit tests are only one form of test we need to perform to verify the application.
A better approach is to start with the most important feature and work your way in from there, using an outside-in approach. This often means starting with some UI.
The way I do it is by creating the desired UI. Since we normally can't develop UI with TDD, I simply create the View with the technology of choice. No tests there, but I wire up the UI to some API (preferrably using declarative databinding), and that's when the testing begins.
In the beginning, I would then TDD my ViewModels/Presentation Models and corresponding Controllers, possibly hard-coding some responses to see that the UI works. As soon as I have something that doesn't explode when you run it, I check in the code (remember, many small incremental check-ins).
I subsequently work my way vertically down that feature and ensure that this particular piece of UI can go all the way to the data source (or whatever), ignoring all other features.
When the feature is done, I can start on the next feature. The way I picture this process is that I fill out the application by doing one vertical slice at a time until all features are done.
Kick-starting a greenfield app this way always takes extra long time for the first feature since this is where you have to wire up everything, so pick something simple (like the initial View of the app) to keep things as simple as possible. Once the first feature is done, the next ones become much easier because the foundations are now in place.
Do I still design up-front?
Not much, no. I normally have an overall design in mind before I start, and when I work in a team, we sketch this overall architecture on a whiteboard or a slide deck before we start.
This is more or less limited to
The number and names of layers (UI, Presentation Logic, Domain Model, Data Access, etc).
The technologies used (WPF, ASP.NET MVC, SQL Server, .NET 3.5 or whatnot)
How we structure production code and test code, and which test technologies we use
Quality requirements for the code (pair programming, static code analysis, coding standards, etc.)
The rest we figure out as we go, but we use many ad-hoc design sessions at the whiteboard as we go along.
+1 Good question
I truly don't know the answer, but I would start with building blocks of classes that I could test then build into the application, not with the top-level stuff. And yes I would have a rough up-front design of the interfaces, otherwise I think you would find those interfaces changing so often as you refactor that it would be a real hinderance.
TDD By Example won't help I don't think. IIRC it goes through a simple example. I am reading Roy Osherove's The Art of Unit Testing and while it seems to comprehensively cover tools and techniques like mocks and stubs, the example so far seem also pretty simple and I don't see that it tells you how to approach a large project.
Do you write the entire application, using nothing but stubbed out code?
To test our systems we mainly do unit, integration and remote services testing. In unit tests we stub out all long running, time consuming, and external services, i.e. database operations, web services connection or any connection to external services. This is to make sure that our tests are fast, independent and not relying on the response of any external service to provide us quick feedback. We have learnt this the hard way because we do have some tests that do database operations which makes it really slow that goes against the principle "Unit tests must be fast to run"
In integration tests, we test the database operations but still not the web services and external services because that can make the test brittle depending on their availability and we use autotest to run the tests in the background all the while we are coding.
However, to test any kind of remote services, we have tests that connect to the external services, do the operation on them and get the response. What matters to the test is their response and their end state if it is important for the test. The important thing here is, we keep these kind of tests in another directory called remote (that's a convention we created and follow) and these remote tests are only run by our CI (continuous integration) server when we merge any code to the master/trunk branch and push/commit it to the repo so that we know quickly if there has been any changes in those external services that can affect our application.
Do I still design up-front?
Yes but we don't do big design up front basically what uncle Bob (Robert C. Martin) said.
In addition, we get to the whiteboard before immersing ourself into coding and create some Class Collaboration Diagrams just to make it clear and sure that everyone in the team is on the same page and this also helps us to divide the work amongst the team members.
I routinely run into this problem, and I'm not sure how to get past this hurdle. I really want to start learning and applying Test-Driven-Development (or BDD, or whatever) but it seems like every application I do where I want to apply is it pretty much only standard database CRUD stuff, and I'm not sure how to go about applying it. The objects pretty much don't do anything apart from being persisted to a database; there is no complex logic that needs to be tested. There is a gateway that I'll eventually need to test for a 3rd-party service, but I want to get the core of the app done first.
Whenever I try to write tests, I only end up testing basic stuff that I probably shouldn't be testing in the first place (e.g. getters/setters) but it doesn't look like the objects have anything else. I guess I could test persistence but this never seems right to me because you aren't supposed to actually hit a database, but if you mock it out then you really aren't testing anything because you control the data that's spit back; like I've seen a lot of examples where there is a mock repository that simulates a database by looping and creating a list of known values, and the test verifies that the "repository" can pull back a certain value... I'm not seeing the point of a test like this because of course the "repository" is going to return that value; it's hard-coded in the class! Well, I see it from a pure TDD standpoint (i.e. you need to have a test saying that your repository needs a GetCustomerByName method or whatever before you can write the method itself), but that seems like following dogma for no reason other than its "the way" - the test doesn't seem to be doing anything useful apart from justifying a method.
Am I thinking of this the wrong way?
For example take a run of the mill contact management application. We have contacts, and let's say that we can send messages to contacts. We therefore have two entities: Contact and Message, each with common properties (e.g. First Name, Last Name, Email for Contact, and Subject and Body and Date for Message). If neither of these objects have any real behavior or need to perform any logic, then how do you apply TDD when designing an app like this? The only purpose of the app is basically to pull a list of contacts and display them on a page, display a form to send a message, and the like. I'm not seeing any sort of useful tests here - I could think of some tests but they would pretty much be tests for the sake of saying "See, I have tests!" instead of actually testing some kind of logic (While Ruby on Rails makes good use of it, I don't really consider testing validation to be a "useful" test because it should be something the framework takes care of for you)
"The only purpose of the app is basically to pull a list of contacts"
Okay. Test that. What does "pull" mean? That sounds like "logic".
" display them on a page"
Okay. Test that. Right ones displayed? Everything there?
" display a form to send a message,"
Okay. Test that. Right fields? Validations of inputs all work?
" and the like."
Okay. Test that. Do the queries work? Find the right data? Display the right data? Validate the inputs? Produce the right error messages for the invalid inputs?
I am working on a pure CRUD application right now
But I see lots of benefits of Unit test cases (note- I didn't say TDD)
I write code first and then the test cases- but never too apart- soon enough though
And I test the CRUD operations - persistence to the database as well.
When I am done with the persistence - and move on to the UI layer- I will have fair amount of confidence that my service\persistence layer is good- and I can then concentrate on the UI alone at that moment.
So IMHO- there is always benefit of TDD\Unit testing (whatever you call it depending on how extreme you feel about it)- even for CRUD application
You just need to find the right strategy for- your application
Just use common sense....and you will be fine.
I feel like we are confusing TDD with Unit Testing.
Unit Testing are specific tests which tests units of behaviors. These tests are often included in the integration build. S.Lott described some excellent candidates for just those types of tests.
TDD is for design. I find more often then not that my tests I write when using TDD will either be discarded or evolve into a Unit Test. Reason behind this is when I'm doing TDD I'm testing my design while I'm designing my application, class, method, domain, etc...
In response to your scenario I agree with what S.Lott implied is that what you are needing is a suite of Unit tests to test specific behaviors in your application.
TDDing a simple CRUD application is in my opinion kind of like practicing scales on a guitar- you may think that it's boring and tedious only to discover how much your playing improves. In development terms - you would be likely to write code that's less coupled - more testable. Additionally you're more likely to see things from the code consumer's perspective - you'll actually be using it. This can have a lot of interesting side effects like more intuitive API's, better segregation of concerns etc. Granted there are scaffold generators that can do basic CRUD for you and they do have a place especially for prototyping, however they are usually tied to a framework of sorts. Why not focus on the core domain first, deferring the Framework / UI / Database decisions until you have a better idea of the core functionality needed - TDD can help you do that as well.
In your example: Do you want messages to be a queue or a hierarchical tree etc?
Do you want them to be loaded in real time? What about sorting / searching? do you need to support JSON or just html? it's much easier to see these kinds of questions with BDD / TDD. If you're doing TDD you may be able to test your core logic without even using a framework (and waiting a minute for it to load / run)
Skip it. All will be just fine. I'm sure you have a deadline to meet. (/sarcasm)
Next month, we can go back and optimize the queries based on user feedback. And break things that we didn't know we weren't supposed to break.
If you think the project will last 2 weeks and then never be reopened, automated testing probably is a waste of time. Otherwise, if you have a vested interest in "owning" this code for a few months, and its active, build some tests. Use your judgement as to where the most risk is. Worse, if you plan on being with the company for a few years, and have other teammates who take turns whacking on various pieces of a system, and it may be your turn again a year from now, build some tests.
Don't over do it, but do "stick a few pins in it", so that if things start to "move around", you have some alarms to call attention to things.
Most of my testing has been JUnit or batch "diff" type tests, and a rudimentaryy screen scraper type tool I wrote a few years ago (scripting some regex + wget/curl type stuff). I hear Selenium is supposed to be a good tool for web app UI testing, but have not tried it. Anybody have available tools for local GUI apps???
Just an idea...
Take the requirements for the CRUD, use tools like watij or watir or AutoIt to create test cases. Start creating the UI to pass the test cases. Once you have the UI up and passing maybe just one test, start writing the logic layer for that test, and then the db layer.
For most users, the UI is the system. Remember to write test cases for each new layer that you are building. So instead of starting from the db to app to ui layer, start in the reverse direction.
At the end of the day, you would probably have a accumulated a powerful set of regression test set, to give you some confidence in doing refactoring safely.
this is just an idea...
I see what you are saying, but eventually your models will become sufficiently advanced that they will require (or be greatly augmented by) automated testing. If not, what you are essentially developing is a spreadsheet which somebody has already developed for you.
Since you mentioned Rails, I would say doing a standard create/read/update/delete test is a good idea for each property, especially because your test should note permissions (this is huge I think). This also ensures that your migrations work as you expected them to.
I am working on a CRUD application now. What I am doing at this point is writing unit tests on my Repository objects and test that the CRUD features are working as they should. I have found that this has inherently unit tested the actual database code as well. We have found quite a few bugs in the database code this way. So I would suggest you push ahead and keep going with unit tests. I know applying TDD on CRUD apps is not as glamorous as things you might read about in blogs or magazines, but it is serving its purpose and you will be that much better when you work on a more complex application.
These days you should not need much hand written code for a CRUD app apart from the UI, as there are a 101 frameworks that will generate the database and data access code.
So I would look at reducing the amount of hand written code, and automating the testing of the UI. Then I would use TDD of the odd bits of logic that need to be written by hand.
I have a J2EE web-application running on Sun hardware with OpenSolaris/Glassfish stack. We're starting our performance bench-marking tests, to prepare for our scalability requirements later.
Any guidelines/best practices would be very useful..
If you are using JUnit? For simple Time Measurement in JUnit there is JUnitPerf which also supports LoadTests. JUnit 4 is not supported very well but it works for me. ContiPerf is an alternative which also supports annotations for easy configuration. I use this before using JMeter.
For a free Open Source tool I've found Apache's Jmeter pretty good:
http://jmeter.apache.org/
As Joe said you'll need to figure out how to model user behaviour and simulate user load.
I'm sure there is many generic ways to test server performance to be found on the web.
But have you thought that perhaps this an opportunity to gather stories and write a test tuned to exactly how your users will use the server? Even if it doesn't perfectly reflect the way that the server will ultimately work, it will let you start learning something rather than being only formal exercise. I think this is the spirit of agile development.
I've been trying to push my mentallity when developing at home to be geared more towards TDD and a bit DDD.
One thing I don't understand though is why you would create a fake repository to test against? I haven't really looked into it much but surely the idea of testing is to help decouple your code (giving you more flexability), trim down code needed and bring down the number of bugs.
So can someone fill in my foolish brain as to why some like to test fake repositories? I would have thought testing against a real database is a much better alternative to creating a fake one because then you KNOW that it works against your real world data store.
The fake repository allows you to test just your application code.
The fake repository means an automated test can easily set up a known state in the repository.
The fake repository will be several orders of magnitude faster than a real database.
The fake repository is NOT a substitute for system testing that will include your database.
As I see it there are two really big reasons why you test against faked resources:
It makes unit testing faster when you have a mocked up against slow I/O or database. This may not look like anything if you have a small test suite but when you're up to +500 unit tests it starts to make a difference. In such amount, tests that run against the database will start to take several seconds to do. Programmers are lazy and want things to go fast so if running a test suite takes more than 10 seconds then you won't be happy to do TDD anymore.
It enforces you to think about your code design to make changes easier. Design by contract and dependency injection also becomes so much easier to do if you've made implementation against interfaces or abstract classes. If done right such design makes it easier to comply to changes in your code.
The only drawback is the obvious one:
How can you be sure it really works?
...and that is what integration tests are for.
I upvoted Giraffe's answer, but want to add just a couple of points:
Each developer can use a mock/fake
repository for her/his own unit
testing without interfering with the
tests being done by other developers
on the same project.
Using a local mock/fake repository
reinforces the user of a data
abstraction layer, which is good
design practice.
As an example, I've used something as simple as a HashMap to implement a mock of the data access layer. This makes it extremely easy for each unit test to ensure that exactly the necessary conditions exist for its purpose, and to verify that the right calls were made on the data access layer.
I am trying to coach some guys on building web applications. They understand and use MVC, but I am interested in other common patterns that you use in building web apps.
So, what patterns have you found to fit nicely into a properly MVC app. Perhaps something for Asynchronous processes, scheduled tasks, dealing with email, etc. What do you wish you knew to look for, or avoid?
Not that it matters for this question, but we are using ASP.NET and Rails for most of our applications.
Once you get into MVC, it can be worthwhile to explore patterns beyond the "Gang of Four" book, and get into Martin Fowler's "Patterns of Enterprise Application Architecture."
The Registry pattern can be useful to make well-known objects available throughout the object hierarchy. Essentially a substitute for using global data.
Many MVC frameworks also employ the Front Controller and the Two-Step View patterns.
The "Model" in MVC is best designed as the Domain Model pattern, although some frameworks (led by Rails) conflate the Model with the ActiveRecord pattern. I often advise that the relationship between a Model and ActiveRecord should be HAS-A, instead of IS-A.
Also read about ModelViewController at the Portland Pattern Repository wiki. There is some good discussion about MVC, object-orientation, and other patterns that complement MVC, such as Observer.
This question is so open that it's hard to give a correct answer. I could tell you that Observer pattern is important in MVC (and for webapplication) and it would be a good answer.About all design pattern that exist are common in big web application. You will require to use some Factory to build complexe object and to access some section require some Facade.
If you want more "tips" or good practice instead of design pattern, I would suggest you to use IoC and the use of good Framework instead of starting from scratch. I can suggest you to explain the benefit of having a good ORM engine to drive you persistance layer faster too (usually can come from the Framework too).
Don't look at it from the aspect of what patterns to use with your development approach, but look at it more as how to apply patterns on a problem-by-problem basis. The architectural decisions made for the project provide just as much indication of what patterns to use as other people's experience will dictate.
That said, I have found that I am a fan of the Provider model for having multiple choices to accomplish a single task with ease of deployment added in. Also, the Unit of Work pattern is great for setting transactional boundaries. Largely, though, the architecture and business needs dictate the approach that is taken for any given code change or new development.
As much as I love patterns, I always fear seeing them overused. I have personally seen people that have used them just for the sake of using them, and it has actually made the code harder to maintain and more tightly coupled than it should have been. Also, it is good to know both sides of the patterns argument. A good pattern knowledge should be rounded out with (often considered a pattern, on its own) anti-pattern knowledge, as well.
I would most likely recommend some kind of Dependency Injection as well (Inversion of Control). Probably the single most important supplementary "pattern" to use.