Given I have written good unit tests for business rule units of a system. Is it still needed to write acceptance tests that target verifying those business rules implementation?
Is it still needed to write acceptance tests that target verifying those business rules implementation?
Yes, it is absolutely necessary.
Your unit tests cover the business rules in isolation. Your acceptance tests verify that the application properly implements those business rules from a customer perspective.
There are many cases where the unit tests of the business rules pass, but problems with integration cause the acceptance tests for those rules to fail.
Update to answer OP's questions:
Unit Tests - test only the unit in isolation. They are not customer-focused.
Integration Tests - test that the units work together. They are not customer-focused.
Acceptance Tests - test that the customer's use cases are complete in a way that satisfies the customer's needs. They are customer-focused, and may be performed by the customer rather than the development team.
Yes you should have scenarios which verify the unit tested business rules.
- good unit tests mock and stub the datastore. Acceptance tests make sure it is configured and works correctly.
- unit tests usually test logic but don't allow for usability and accessibility
- unit tests don't test whether the application works on the vast array of devices and browsers that are available today.
- many of the problems that plague systems are due to software configuration management and require acceptance testable systems that reflect production configuration, frequently on a 'staging' server. Developer setups do not usually reflect the production configuration.
Good unit tests are not interchangeable with acceptance tests. They are different concepts and serve different purposes.
- Unit tests, as its name suggests, they are aiming at testing individual units. Besides, how do you define "good" unit tests?
- Acceptance tests are carried out as if you were a customer, you would expect all individual units of your code have been integrated together; if you do not execute acceptance tests, how would you detect communication issues between units?
Yes, most of the time you do.
Personally I have implemented some new features TDD, with 100% unit-test coverage on my classes, but I forgot to update the implementation code that was used during the bootstrapping. I needed to add a couple of integration-tests to cover this situation.
Eventually you also want to check the full end-2-end stack with a couple of tests. If not only to make sure that if something breaks you can add these types of tests in a later stage. For example when something is hard to test at unit level. If you do not create end-2-end tests from the beginning you might realize to late that you build your UI untestable or just very hard to test.
You do need to find a good balance between different test types, read about the test pyramid. Still focussing mainly on unit-tests is good, but just not good enough.
As others have mentioned, unit tests cover functionality in isolation. There's a great little illustration of why that's not enough that's gone around recently. It can be seen here: https://www.youtube.com/watch?v=0GypdsJulKE
Now, that's funny and it makes for a great joke, but there's value in remembering that your code doesn't live in a vacuum. Software is made up of components that must work together. Unit testing is about isolating a single component and making sure that it behaves the way it should. Integration and acceptance testing is about making sure that components work together to meet the acceptance criteria and, by extension, the business need.
Unit tests and integration tests are designed to facilitate the development of the product. Oversimplifying in this area can lead to difficulty in regression testing and failure/fault isolation, regardless of where a problem is first discovered.
Acceptance testing is usually done in a manner agreed to by the end user or customer and is solely focused on the functional and performance results that they expect to see. Acceptance tests are not intrinsically expected to be used in failure isolation, even when the failure is discovered as part of the acceptance test. They may be used to gather insight to what may have caused the failure, but should not be so complicated that they are also expected to be used to determine a root cause in the software.
Note that a failure in an acceptance test may not be due to a fault in the software. It may be due to an error in understanding the requirements and implementing incorrectly. Unit tests and integration tests will not necessarily uncover this type of failure.
Good unit tests are your first line of defense. But as any strategist can tell you, one line of defense is never enough. You expect that some of your unit test will fail to catch some issues (or it is hard to write a unit test for, or test coder did not thought about some combination, or error happened in unexpected way - there are many reasons) so you have higher-level tests.
It is called "defense in depth" strategy. Read up on strategy. Sun-Tzu is a good start for more than 2 millennia :-)
Unit tests and acceptance tests need fundamentally different approaches
Unit tests check that your code does was you think it does, but not whether that is the correct thing to do. A good unit test checks that you have implemented the low level structure of your functions (or units) without any straight-forward errors.
Acceptance tests check that the combination of your little units of code is doing something that is overall sensible and correct for your use case. You've verified that your code does what you expect it to with unit tests, but acceptance tests help to check that your mental model is correct, and that the code you've written actually solves the problem you set out to solve.
Would you buy an keyboard whose every key has been tested but somehow does not work with your computer system?