I have a confusion regrading the definition of unit test.
I think unit tests is about mocking external dependencies, the scope can be large like IT test (more than one class).
In this way of thinking, I can test in my UT complete flow and that can help me catch bugs fast, (I'm not using Spring, I'm not using external dependencies),
I want to catch bug fast because if I'm doing refactoring, I want to run my tests every few minutes to see if something's broken so I need my tests to run fast. (That's why I only want to run UT and not IT tests).
It seems that in the industry, when talking about UT, UT should be small (scope), and also mock external dependencies.
I don't think this is a good way of thinking, because that means that my UT can miss bugs that IT catches, which means that running only UT every few minutes is not good enough and I should run IT tests which is much slower which is not good for me because the refactoring process will take me much longer.
So what Am I missing something? Why not to write UT that tests complete flows just like IT but with mocking of external dependencies?
Thanks
Definition: Unit-testing is the testing method that aims at finding or preventing those bugs which are detectable by the testing of small (even minimally small) isolated pieces of software.
This definition sets the lower bound for the scope of unit-testing, namely starting from the smallest pieces of software. For the upper bound it leaves a degree of freedom. Sometimes people try to also delimit the upper bound by coming up with definitions for the term unit. But, I do not care so much what a unit is. Instead, I set the limit based on the question how big the software piece under test can be such that the unit-testing methods still can be applied sensibly.
For example: A single function of, say, 15 lines of code would be subject to unit-testing. But, what if I refactor my code such that from the function two helper functions are extracted? According to the defintion I could now also apply unit-testing to the helper functions. But, if I already had a perfect suite of unit-tests, these should still work with the original function's interface. Thus, I could keep my tests and ignore the changed internal structure - and it would still be unit-testing.
Another example: In C++, container classes come together with related iterator classes. The container class and its corresponding iterator classes are tightly coupled. Testing these classes jointly with unit-testing methods will work nicely in many cases. When testing the iterator, you would normally not isolate it from its container class, but rather test both together - and I still consider this to be unit-testing.
Summary part 1: As long as applying unit-testing methods makes sense, you can also apply it to sets of tightly coupled functions and even tightly coupled classes.
Looking at the above definition again, it mentions isolation. Note, however, that isolation here is used to classify the type of bugs that can be found: Unit-testing is for findings bugs that can be found in the isolated software. It does not state that you actually have to isolate the code during testing. In other words, you do not necessarily have to mock the dependencies.
Mocking should be done for a reason. If you consider mocking a function or method, you should know which problem you are about to solve. If there is no problem to solve, don't mock. For example, you also don't mock standard library math functions like sin or cos, because they also don't cause problems in most cases.
You would do mocking, for example, if the depended-on-component (DOC) causes non-determinstic behaviour (randomness, time, ...). With mocks, however, you can not find those bugs, which are related to misconceptions about how the interaction of the function under test with the DOCs should work: Since you implement the mocks, you implement them based on your potential misconceptions. This is not a flaw of unit-testing: It is just the reason why in addition to unit-testing you also need integration and system testing.
Summary part 2: Unit-testing is not necessarily about mocking. It is about focusing on finding a special kind of bugs: Those you could find if the code was isolated. This leaves all other bugs (and especially those you can only find in the integrated software) out of the scope of unit-testing.
Usually unit test is a test which covers single method of a single class.
In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method (https://en.wikipedia.org/wiki/Unit_testing)
One difference is what people consider to be a unit. Object-oriented design tends to treat a class as the unit, procedural or functional approaches might consider a single function as a unit. But really it's a situational thing - the team decides what makes sense to be a unit for the purposes of their understanding of the system and its testing. Although I start with the notion of the unit being a class, I often take a bunch of closely related classes and treat them as a single unit. Rarely I might take a subset of methods in a class as a unit. However you define it doesn't really matter (https://martinfowler.com/bliki/UnitTest.html)
Usually you have unit tests which cover small pieces of code and integration tests that test integration between several classes/modules. And you run unit tests much more frequent then IT tests.
The purpose of small unit tests is to locate piece of code that caused bug as precise as possible. if your It test which uses several classes fails then you need to check all those classes one by one to find an issue. But if your unit test which covers single method of single class fails then you know exactly where the issue is.