Here's my perspective:
Unit Testing
tests a single unit - usually at the routine level (that is, only one unit of code such as a function is tested). Unit tests are typically code-based, written by developers, and executed whenever the application is compiled or built.
Module Testing
tests a single chunk of functionality in isolation, such as testing the features of a single page in a web application. This sounds like what you're calling unit testing.
Integration Testing
tests that newly added/modified features work in the context of the application. This is very similar to module testing, but can be a bit larger in scope, such as when you're testing two modules interacting. I've also seen this level called feature testing. I personally consider it feature testing when tests are covering whether the feature works as it should, and integration testing when tests are checking whether the feature was properly integrated into the system and all the required changes are present.
System Testing
tests end-to-end flow through the entire application, including data storage, the impact of new features on existing features (things like making sure that a new data type is handled in other places it can be used, that data isn't lost when moving between the new features and existing features, and so forth), and the overall look and feel of new features (particularly whether the look and feel works for new users and whether it fits the rest of the application).
There's quite a bit of overlap between all classes of testing because the main difference is the scope of the testing. I've seen any tests written by a developer to be run at compile-time be considered unit tests even though they exercise multiple routines within the code. In my opinion, it doesn't really matter.
It helps to know what the usual definitions are, but ultimately the goal is to learn as much about how the application behaves with the new features as you can in the time you have. If classifying your tests by scope helps with this, then do it.
For your second question, why do you need to write separate tests for the highest level of testing, the reason to write separate tests is that you are looking for different information. At the lower levels you are looking at how the new feature works in isolation. At higher levels you're looking at how information flows through the application and how it's stored.
Example: testing a web store
Consider a web store application. Here are some examples of the kinds of things that would be tested at each level.
Unit Tests
Typical unit tests might be:
- Calling the AddToCart routine and verifying that the items have been added in the given quantity.
- Calling the CalculateTotal routine for a known set of items in a shopping cart and verifying that the total matches the expected result.
- Calling the RetrieveItems routine and verifying that the list of items returned matches what it should be (if this is run against a database containing the item list, it could be considered a module test or integration test)
They're all testing a single discrete function.
Module Tests
Typical module tests might be:
- Opening the product list page and checking that all the products you expect are on the list
- Checking that each product allows you to enter a quantity and add it to the shopping cart
- Checking that all the information you expect to see about each product is displayed in the format it should be displayed in.
- Checking that everything that should be in a shopping cart is displayed
Here, you're focusing on one small chunk of function and don't really care where the data comes from or how it got to the page.
Integration Testing
Typical integration tests might be:
- Entering different quantities of items on the list page, then adding them to the shopping cart and checking that the shopping cart displays those items.
- Modifying the quantities of items in the shopping cart then selecting Checkout and verifying that the total you're being charged matches the total shown by the shopping cart after you'd modified the items in it.
You're still working more or less in isolation, but you're dealing with the communication between two or more modules.
System Testing
The tests I'd be running here would be things like:
- Cancel sale
- Browse items and make some selections, then add them to my shopping cart.
- Check the database to make sure my selection is stored as a temporary/potential order.
- Edit my shopping cart. Check that my changes are saved to the database.
- Cancel my order. Check that the database throws away my selection.
- Complete sale as a known customer
- Browse items and make some selections, then add them to my shopping cart.
- Check the database and make sure my selection is stored as a temporary order.
- Log on to the web store.
- Check that my temporary order in the database is updated with my customer details.
- Select check out. Make sure that my saved payment information is pre-loaded and selected by default.
- Select the default payment option and complete the purchase. Check that my order is updated to be a real order and flagged as unfulfilled.
Here I'm testing the process from beginning to end and making sure that each part does what I expect it to.