Unit tests are tests written by developers alongside the code. The size of a “unit” depends on the programming language, the design, and the domain of the problem. In other words, there’s no rule that a function/method/procedure/module/class constitutes a unit.
Unit tests have the following properties:
They’re self-verifying, which means that no living person should ever have to verify whether a unit test was successful or not. This is the cornerstone of automated checking. A unit testing framework’s assertion mechanism ensures this property.
They’re idempotent, i.e. repeatable and consistent. In other words, they can be executed over and over again and still produce the same results.
They’re automated so that they require no manual steps in their execution. This is a prerequisite for continuous integration, and is taken care of by the unit testing framework.
They test a single logical concept. This is related to the size of a unit. A unit test exercises one operation/condition/concept/state change so that it’s obvious where a defect has been introduced.
They run in isolation, simply meaning 100% controllability. As a consequence, unit tests cannot talk to databases, file systems, network sockets or any remote endpoints of any kind. They must also be completely environment-agnostic and have no requirements on parallel execution or absence thereof.
They’re fast. Fast is a bit subjective, but generally speaking, a normal workstation should be able to run thousands of tests in just a few seconds. This property is usually not a problem if the preceding ones have been satisfied, especially isolation. The corner case is long-running tests of complex algorithms. Such tests may in truth be unit tests, but it may be beneficial to keep them out of the unit test suite anyway.