I'm sure everyone who's worked in a software company has, at least once, heard this question or maybe even thought about it. Analyzing a bit further, it becomes obvious that the question makes no sense as the two types of tests don't perform the same function. We need acceptance tests, and in modern times we'd like them to be automated. The actual question you might have heard is "Who will implement the acceptance tests?" and the answer to this will vary depending on your company / team direction. In my opinion, which happens to coincide with the company's and the team's opinion (yey!), everyone in the team should do it.
Yes, even the PM has a very important part here in formulating the requirements in an easily translatable to Gherkin language format. Every time we talk about it, this question always pops up one way or another "But if everyone on the team should write tests, shouldn't everyone on the team write code?". Sure, testers should and do write code. Automated acceptance tests are code, they go through the same review process and are part of the code base. Will testers pick up development tasks outside of tests? Some will and some won't, but it's not like there's a coding deficit we need to cover. I'm sure you've heard that for every tester there are 3-5 developers on a team. You've heard it because it's mostly true although I'm sure there are exceptions. The tester, QA, SDT or whatever title this staff has in your company, they usually have enough on their plate and they can't really get into tasks outside of testing because that would create a testing deficit and the project would suffer. Don't get me wrong, I'm not complaining, I like the fast pace, but for some reason, writing tests is frowned upon by most developers. Maybe they feel like it questions their brilliance or doubts their competence, but, for a confident and experienced developer, they bring value to their work and save time on validation.
From another point of view, if the developers write acceptance tests too then the tester can invest more time on other project areas, like in doing deploys which lately can be done in one click. As you know, in the software development world, the main goal is to have automated environments and, in this way, you can have continuous delivery. So, if developers are writing acceptance tests, and all of them get integrated in the deployment pipeline or nightly deploy, all of them covering all project functionalities, then what will the tester do? Won't we get to a point where it wouldn't be that clear what the differences between the developers and the testers are? In the current world, you can't really find that many projects which really get to that maturity level, when the continuous delivery process is at its maximum and everything goes smoothly live. In this case, the tester also has to do manual types or testing which will take some time, considering the amount of features delivered by the development team. Moving away from this utopian situation and getting back to the normal world, it would be desirable that each developer would cover the feature that he is delivering with tests, at least unit and acceptance tests.
Maybe you're wondering where I'm going with this. Do I want you to write more tests? Of course I do, I'm a tester, but more than that, I want you to like it and see the value in it. You've probably already seen the value in writing unit test and, although you still might get a little frustrated on a pull request when someone comments "shouldn't this have unit tests?", you find that once they're written they make your life easier. Well, with acceptance tests it gets much better. Not only do they find your potential mistakes, but they find other people's too and what's better than pointing fingers? Joke aside, writing acceptance tests will force you to better understand the business requirements, it will make you aware of infrastructure issues, it will provide end-to-end integration coverage and will also give you some performance insights.
So why doesn't everyone just write acceptance tests? This happens because the world isn't black and white, it's all shades of gray (more than 50 probably) and each type of test has its uses, its benefits and its downsides. I'll only discuss acceptance tests and how they can make you a better developer. Let me try to "sell" acceptance tests to you. I won't get into the whole "cheaper, faster, more reliable" mantra that you've probably read or heard countless times, but I'll try to give you a more personal view based on my experience so far.
You can cover a lot of functionality with a well-written acceptance test. For a typical web application, you could cover most of the business critical parts in around 10 smoke tests. These will integrate into your deployment pipeline and will give you confidence with every release that goes to production. You'll mostly find environment, dependency, integration or even DB issues (because you've already covered the basic logic with unit tests, right?), but those will be important issues. I'm sure, in a perfect world, the perfect code gets perfectly deployed to the perfect virtual machines and runs perfectly on each environment, but we don't live in a perfect world. In the real world, you're always using someone else's API that they sometimes make changes on and don't notify you (because why would they?), or some Azure machine is acting up or somehow got misconfigured or someone moved a column in the DB and now you can't get your data, or a million other things that can go wrong (and which Murphy says will go wrong eventually) and acceptance tests will fail in all of these cases. Can you cover that with unit tests? You're maybe thinking: "No, but my job is to write good code!". Not really.. All our jobs are to DELIVER good code and if we get stuck on the factory worker mentality who is only responsible for his small part, that's how we'll be treated.
Once you start writing acceptance tests you'll understand much more of the business logic. You'll have to figure out exactly how the user should be working with your app and you could even identify potential improvements. Your PM created some flows and imagined the end result. You implemented them according to the requirements. Now, once you get into acceptance testing, you'll see how you can make those flows more efficient because you want the tests to run as fast as possible, and you'll also see exactly where the app is slower or where you could make it easier to use. So what's it like writing acceptance tests? It can't be that hard if a tester can do it, right? Well, the writing is the easy part. Unlike unit tests, running browser tests using a web driver from a virtual machine or build agent on a web app can sometimes fail without obvious reasons. Here comes the maintenance and debugging part. Please don't get too upset about it, it happens to everyone and in time you'll learn to avoid the common issues and deal with the slight flakiness and, in the end, you'll have very stable and very valuable tests. Just give it some time and effort and they'll reward you.
Now you've started writing acceptance tests and are loving it, right? Now the problem is you have too many. You can no longer use them as smoke tests in the pipeline because they run for 2 hours. What can you do? Well, this is the point where you should invest time into getting a nightly build up and running. Although it's called a nightly build, it doesn't mean you have to build the entire solution, you can just build the automation pack, run it on the latest deployment and, in the morning, you'll have the report waiting for you. Seeing everything green on the report while you sip on your fresh coffee is the best feeling in the world, but don't get too fond of it. Tomorrow you'll probably have some red ones and that's OK, because that's why you wrote them. Trust me, they'll make your app better in the long run.
To conclude this kind of long rant, I'll try to give everyone a bit of advice. If you're a tester, start or continue writing automated acceptance tests. They'll make your job easier and also give you insight on what developers do and how they do it. If you're a developer, start writing them for all the reasons I already gave you and in order to deliver (not just code) great applications. If you're a PM, look at how some tests are written and try to emulate the BDD phrasing. The rest of the team will appreciate it and will better understand your vision. If you're already doing all of the above and enjoying the results, you're awesome, keep at it!
Now that the reason behind writing acceptance tests is clear, you can just think about the huge value that unit tests can add to your project. From a developer's point of view, we all know that, for the project to be valuable in the long run, you will have to maintain it, add features that come out of the user's feedback or out of the latest project needs. Let's just assume you don't have that much code coverage, and you want to add a really important feature to an already existing important part of the application. You will obviously try to have that implemented in the most efficient way, also using the opportunity to refactor a bit of code to keep it clean once the new piece of logic gets integrated. Everything's going well, you are happy with your good-looking code, you deliver the new feature being happy that you've done it in time, and suddenly the PM or a user comes to you complaining about an existing feature that's not working anymore. Of course, being already convinced about the importance of the acceptance tests, you will definitely say that you should have caught that issue from the acceptance tests runs, but what if that piece of functionality wasn't covered in any acceptance test because, let's say, it wasn't that important at the time when the acceptance tests were written? We all have to admit that this can happen. Also, even if you are focused on having everything unit tested, you might skip some logic, because yes, we are humans, we forget and we make mistakes. It happened to me to have a new piece of logic added to an API endpoint, that piece of code wasn't properly unit tested, and the acceptance tests run got somehow skipped at deployment time. We ended up almost to the production environment, passing the continuous integration one with success, and being just lucky that the Pre-Production run had a failed acceptance test result. After almost one hour of investigating the logs, test result messages and stack trace, DB changes involved, API access, we got to the deepest level of the application, a piece of a method in a service class where the developer missed a piece of logic which just returned the "not found" result for no reason.
If you are thinking of that specific situation, now that you see the importance of the acceptance tests, you might also think that the issue could have been found by the developer even before the code got in the pull request. And yes, in such cases unit tests will make the job easier for a tester, and also easier for the developer in the future, when they can add anything new, run the unit tests, and be sure that nothing was broken. Besides, the unit tests help in having a proper code design and project architecture very much, by putting you in the situation where you have to write decoupled components, following the SOLID principles and the design patterns applicable to your project. All these benefits also come with the one of having documentation for the developers by allowing them to read code (the unit tests) and understand what that specific component does.
Now that you have a lot of ways to compare and decide what type of testing you need, you just have to go and practice a bit to make the best decision for your project needs. In theory, all types of testing help and if you have as many of them as possible, then you can sleep without stress. But, in practice, the project needs will tell you what you have to adopt as testing strategy. In fact, you just have to think and assess together with your PM/architect/tech lead the value that you add to the project if you implement one or two, or many types of testing. You don't want to invest most of your time in tests if they don't bring value, and risk not delivering the features as expected by the business. From my experience, at least unit tests & acceptance tests should be implemented in every project, and, if everyone from the team is implementing acceptance tests, then you can be confident about your application and each live release.
Now go and do some experiments! Write valuable unit tests for the sake of clean code, long-lasting code design and maintainable code for those times when you're not having your best day and you might miss something. Go and write business valuable acceptance tests, no matter if you are a tester or a developer. Get to know your application's business from top to bottom, and everything will become easier with every new feature you are implementing!
Happy developers lead to happy testers which lead to happy PMs and finally to happy users! And happy users will make this a better world.