Unit Tests Should NOT Be In Your Coding Evaluations
Tags: testing, career, webdev, programming
Published: 2023-03-15 16:22:43

I've remained silent on this topic for far too long.  But now I'm about to go off.  Buckle up...

In the last few weeks I've had some experiences with unit tests during coding evaluations that have left me exasperated and infuriated.  This isn't the first time that I've run into these types of issues.  But I'm finally fed-up enough to proclaim loudly and proudly that:
<br/>

> _Unit tests should have no place in the coding evaluations that you foist upon prospective candidates._

<br/>That may sound like heresy to some of you.  (HINT: I don't care.)  But if it really bothers you _that_ much, there's a good chance that you're part of the problem.
<br/><br/>


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jjey0kgbpsve7zrvx3z3.jpg)
## I'm not a heretic
Before I explain exactly why unit tests should play _no_ part in your coding evaluations, I want to make it clear that I'm not taking a stand against unit testing in general.  _Of course_ you should be using unit tests in your dev environment.  _Of course_ you can vastly improve the quality of your coding efforts through copious unit testing.  _Of course_ you want all of your devs to be comfortable with unit testing.

So _of course_ you should be including it in all of your coding evaluations...  _Right???_

**NO.**  

Allow me to explain...
<br/><br/>


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/je0nx24lbt8fge30hjcl.jpg)
## Writing tests wastes time and can be disrespectful to the candidate
During the normal day-to-day operations in your dev environment, it's typically unacceptable for someone to say, "I finished this task and submitted the work - but I didn't write any unit tests because I simply ran out of time."  During normal "dev operations", a task isn't actually _done_ until you've accounted for proper testing.  But this standard should _not_ apply during coding evaluations.

Most coding evaluations are timed.  They give a set period in which you must fix a bug or build a feature or alter an existing feature in some way.  Often, these time constraints can feel daunting - even to senior devs.  

Imagine you have one hour to build some feature in React.  Maybe it's not _that_ hard.  Maybe you're feeling pretty confident that you can knock this out.  But in the middle of building it, you run into _some_ kinda bug.  You know... the kind where you sit there for a few minutes and just think, "Wait... What the heck's _going on_?"  Maybe you forgot to hook up a key handler and it takes you some time to realize what you've overlooked.  Maybe you just made some stupid typo that's not immediately apparent in your IDE.  Regardless, the point is that, even in the simplest of tasks, sometimes you can "burn" 10-15 minutes rectifying something that you screwed up.

Eventually, you _fix_ it.  And you go on to build the complete feature right under the hour deadline.  In fact, you built it _well_.  You're feeling pretty confident about the code that you cranked out.

But you didn't get time to add any tests...

If your code is solid, and you completed the task, and you demonstrated a solid understanding of React, there's no way in hell you should ever be marked down (or eliminated from contention) merely because you didn't _also_ have the time to slap unit tests onto your solution.

Let me be absolutely clear here.  The mere act of _writing_ a unit test is generally quite easy.  Most of the testing frameworks have very similar syntaxes and they're designed to help you write tests in a way that makes semantic sense. They use verbiage like:

```javascript
it('Should enqueue the items to the queue', (done) => {...});
```

and 

```javascript
onDequeueSpy.calledOnce.should.be.true;
```

So it should feel fairly natural (to any established dev) to write tests in this manner.  

But even though they can be syntactically self-explanatory, it can still take a little... _nuance_ (and _nuance_ equates to: _time_) to add unit tests that are actually meaningful and properly account for edge cases.  The _time_ it takes to implement these should not be a burden in your normal dev cycle.  But it's absolutely a burden when you're staring down a timer during a coding evaluation.

A few weeks ago I completed a coding test where they wanted me to add _a lot_ of features to an existing React codebase.  And they told me that it should all be done... _in 45 minutes_.  It wasn't just that I had to add new components and get all the event handlers hooked up, but I had to be careful to do it in the exact _style_ that already existed in the rest of the codebase.  Furthermore, there were numerous CSS requirements that dictated precisely how the solution should _look_.  So it wasn't enough just to get the _logic_ working.  I also had to get everything matching _the design spec_.  And again, I had to do that all _in 45 minutes_.

But of course, this wasn't all they wanted.  The requirements also said that all existing tests should pass _and_ I should write new tests for any additional features that were added.  And I was supposed to do all of that _in 45 minutes_.  It was patently ridiculous.

If I've coded up a fully-functioning solution that meets the task's requirements, but I didn't get time to put proper unit tests on my new features, and you _still_ want to eliminate me from contention, then... _good_.  Believe me when I say that I don't wanna work on your crappy dev team anyway.

But these aren't the only problems with unit tests in coding challenges...
<br/><br/>


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9kriszhyhq765uo4k29o.jpg)
## Broken tests
So maybe you're not asking me to _write_ tests.  Maybe you just have a buncha unit tests in the codebase that need to pass before I can submit my solution?  Sounds reasonable, _right_?  

Well...

On numerous occasions, I've opened up a new codebase, in which I'm supposed to write some new solution, and found that the tests don't pass _out-of-the-box_.  Granted, if the "test" is that the codebase contains a bug, and the unit tests are failing _because of that bug_, and you now want me to fix that bug, then... OK.  Fine.  I get it.  

But I've encountered several scenarios where I was supposed to be building _brand new_ functionality.  Yet when I open the codebase and run the tests that only exist to verify _the legacy functionality_ - they fail.  So then I spend the first 15 minutes of my precious evaluation time figuring out how to fix the tests _on the base functionality_, before I've even had a chance to write a single line of my new solution.

If this is the kinda test you wanna give me, then I don't wanna work on your crappy dev team anyway.
<br/><br/>


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pjbwudpyq8vytg85d3il.jpg)
## Secret requirements
Here's another `<sarcasm>`delightful`</sarcasm>` headache I've run into from your embedded unit tests:  You're not asking me to write _new_ unit tests, but you've loaded a whole bunch of tests into the codebase that are designed to determine whether the new feature I've built performs according to the spec.  So I carefully read through all the instructions, and I crank out a solution that satisfies _all of the instructions_, and it runs beautifully in a browser, but then I run the tests...

And they fail.

Then I go back and re-read all of the instructions, even more carefully than I did the first time.  And - lo and behold - I've followed the instructions _to a tee_.  But the unit tests still FAIL.

How do I remedy this?  Well, I've gotta open up the unit test files and start working backward from the failures, trying to figure out why my instructions-compliant solution still fails your unit tests.  That's when I realize that the unit tests contain _secret requirements_.

For example, I ran into this scenario _just yesterday_.  The React task had many features that should only display conditionally.  Like, when the API returns no results, you should display a "No results found" `<div>`.  But that div should not display if the API did in fact return results.  And I coded it up to comply with that requirement.  But the test still failed.

Why did it fail?  Because the test was looking, hyper-specifically, for the "No results" `<div>` _to be NULL_.  I coded it to use `display: none`.  The original requirement merely stated that the `<div>` should not be _displayed_.  It never stated that the resulting `<div>` must in fact _be NULL_.  So to get the test to pass, I had to go back into my solution (the one that perfectly complied with the _written_ instructions), and change the logic so it would `NULL`-out the `<div>`.  

I had to do the same for several other elements that had similar logic.  Because those elements also had their own unit tests - that were all expecting an explicit value of `NULL`.

If this had been made clear to me _in the instructions_, then I would've coded it that way from the beginning.  But it was never stated as such in the instructions.  So I had to waste valuable time in the coding test going back and refactoring my solution.  I had to do this because the unit tests contained _de facto_ "secret requirements".

If you can't be bothered to ensure that the unit tests in your coding challenge don't contain secret requirements, then I absolutely have no desire to work on your crappy dev team anyway.
<br/><br/>


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ehdwg4fft62csy6mnba.jpg)
## Illogical unit tests
Maybe you're not asking me to crank out _new_ unit tests, and maybe you're not hiding "secret requirements" in your unit tests, and maybe all of the tests tied to the legacy code work just fine out-of-the-box.  So that shouldn't be any problem for me to comply with, _right_??

Umm...

Yesterday I was coding an asynchronous queue in Node and I ran into a series of unit tests that displayed intermittent failures.  These failures happened because the exact timing of the unit test's queue checks were set on extremely tight intervals.  Sometimes, all the tests would pass.  Sometimes, one or two would fail.  It was basically... random.

Of course, one easy way to "fix" this issue is to give these calls a little more breathing room.  _But you can't update the test files._  If you try to do so, your `git push` is blocked.

I played around with this for _a long time_, trying to get it to consistently work without altering the test files.  To no avail.

During the exact same exercise, I ran into a series of tests that would fail if you'd programmed the queue-pause feature in a certain way.  But they'd pass if you wrote it in an entirely different way.  But of course... there was no mention of the required (but hidden) way that they wanted you to program the pause feature.  So you had to figure out through trial-and-error after the tests failed.

Of course, it doesn't matter that these unit tests were janky AF.  All that matters to the evaluator is that the (illogical) tests didn't pass.  

In the end, I suppose it's a good thing that they use these illogical tests, because guess what?  I sure-as-hell don't want to work on their crappy dev team anyway.  But I'm still annoyed as hell because I wasted hours of my time yesterday doing their challenge, after I'd already had a great live interview with them and after I'd already coded _a working solution_, because they can't be bothered to write logical unit tests.