My opinion is always be careful with people saying things like: "Never use X", never is a really strong word. The right statement should always be: "use X correctly". Or at least explain in which situations X is a valid approach and in which it's not. Great video as always.
@pzodeosrs2 ай бұрын
Only Siths deal in absolutes!
@bloodgain2 ай бұрын
The programmer's "never" isn't really never, it's just strongly-worded advice against something. It means "this is a rule you should only break if you know all the reasons you shouldn't do it, understand the pitfalls and risks, and can still articulate why it's the best choice". It's a nice way of saying, "you're probably not a good enough programmer to break this rule", and it's true because most programmers who break the rule do so at the wrong times because they lack experience, understanding, or both. Popular examples of this are "never use" global mutable data and goto -- which anyone with experience and understanding knows someone, somewhere has to break, or we'd have no useful software. It's almost exactly the same situation as telling a young child not to do something. It doesn't mean _nobody_ should do that thing, it just means the child shouldn't do it, and the reasons are too complex to explain. When they get older and more experienced, the advice can get more nuanced: "Don't talk to strangers" becomes "you shouldn't trust a stranger who wants something from you, but if you need help, find the nearest adult" becomes "most people have good intentions, but some people want to harm you or trick you, so if you aren't sure, ask another adult you trust first" becomes "try to determine what the person's motives are, and the risks to you, and decide if you can accept that risk".
@Eregrith2 ай бұрын
Never use GOTO
@Zullfix2 ай бұрын
Never use dynamic.
@Zullfix2 ай бұрын
@@EregrithLook up goto switch case for C#. Goto is not a bad language feature.
@Thial922 ай бұрын
Ah yes instead of just mocking a service write a full custom implementation for each particular test and pollute your codebase with garbage.
@mirata92 ай бұрын
Yeah that way when your test fails, you get to spend your day figuring out if the bug is in the thing you wanted to test, or the fake you had to write to get there
@moveonvillain10802 ай бұрын
Employment safety mechanism.
@Mutex302 ай бұрын
But I love writing and maintaining my entire production system twice! I think the guy who gave this advice must get paid by the number of lines of code written.
@tomasgutierrez69542 ай бұрын
...then you'll have to make it so generic that you have basically reimplemented an in house mocking library.
@deyanvp2 ай бұрын
@@Thial92 can you guys imagine that a function dependency can be mocked by simply ... providing a mocked function with a single line of code, eg in F#. Not needing any mocking library with fluent API for that ... and even if I need such one day, that would be just an impl. detail ...
@sleeper-cassie2 ай бұрын
A someone who is Very Old, there’s something about the anti-mock arguments going around that’s reminiscent of the anti-unit test arguments that were going around 20 years ago. Lots of motivated reasoning and contrived examples that exist to emphasize “wasted time” and “duplicated effort”. The number of posts I read that were built entirely around the example of unit testing getters and setters…
@CarnesSurefire2 ай бұрын
The best thing about fakes over mocks is they can be easily added to your DI framework and your tests can construct objects the exact same way as the prod code. Then when someone changes the SUT constructor it won't require going to every single test class with mocks to fix the construction. Mocks are only good for extremely small tests. Anything integrated should be done with the real classes as much as possible and fakes where necessary. Then once you have some excellent fakes there's very little reason to use mocks.
@Mr7672672 ай бұрын
Correct!
@NoMis88822 ай бұрын
I have to kinda agree with the general sentiment of the original post actually. It just does not really explain very well the reasoning behind the argument. You should look up "Stubs and mocks break encapsulation" blog post by Mark Seeman where he explains exacly the problem that mocks may cause. The general idea is, that a test double actually implements the interface contract so it behaves the same. When the code of the system under test changes a specific way (while still fullfilling it's contract) it might work with the original implemenation of the dependency that fullfills the contract but may fail with the mock and you need to change a whole bunch of tests to make them pass again. Just because a test passes does not mean that the test is actually correct.
@sk1f232 ай бұрын
the situation where same contract (interface) works in one scenario (unit tests) and fails in another (actual implementation) suggests that the code is actually coupled on the implementation/side-effects rather on the interface(s). This sounds like a problem worth solving rather than declaring that mocks are bad, unless I'm misreading the explanation.
@omoton8022 ай бұрын
I think the original post is missing the point of mocks. Its not to mock everything, it's to isolate the functionality you are testing and mock everything else that you want to behave the same way each time. I think of tests like a tiny bit of research. You want to identity your dependant and independent variables then mock stuff that doesn't change between test runs.
@NoMis88822 ай бұрын
@@sk1f23 The coupling in this case is rather between the mock and the unit test. The mock might be coupled to the unit testing code in question because it does not follow the original contract correctly. It is rather specifically setup to allow the current code to pass. The problem arrises, when changes to the code would not break the implementation, and are thus valid, but break the mock. Meaning the mock does not represent the interface correctly. The implementation code is not coupled to the implementation of the interface. But it is of course dependent on the interface contract.
@z0nx2 ай бұрын
@@sk1f23 For example, an implementation that is being tested needs a user and calls repo.GetUserById(id). Then in the future changes it to repo.GetAllUsers(). Now if you had set up the test with a mocked GetUserById, the test will actually fail (it now needs to set up GetUserById), while with a fake this wouldn't be the case. Extrapolate this situation to 100s of tests, each with their own mocked setups, and you will realize how silly it is to be doing it that way. Then add the fact that an interface usually comes with an implicit contract. For example .GetUserById after doing an .AddUser should return the added user. With mocks you have to encode this contract in each test, while with a fake you only write that once, and you write that logic outside of the tests.
@stevenodlum45632 ай бұрын
Use mocks for unit tests, use 'fakes' for integration tests. What I mean by that is create mocks for only the services that reach out to 3rd party connections in some way when doing unit tests because you are only testing the behavior of a single function/method in the entire code base. When doing integration tests, setup a fake database with fake data and fake 3rd party connections to simulate the real world interactions as much as possible. Each approach has it's own use case and it doesn't make any sense to idealize one over the other.
@moveonvillain10802 ай бұрын
Sounds like something I read in "Learn Go with Tests"
@parsarnblad11072 ай бұрын
Agree on this. Also fakes can be used in a lot of scenarios, ie repos can be faked and be used in demos, during devlopment and so on.
@alexeykostylev39982 ай бұрын
the question is - what logic are you going to test. What would be a difference between unit tests and integration ones? Presence of fakes? In my view the key point is - what are we going to test. What lines of code exactly. and then decide on level of abstraction - mocks, fakes, real services pointed to sandboxes
@condar152 ай бұрын
So as I've developed as a developer I'm seeing more use of a simple stub (or "fake" if you prefer) than mocks. That doesn't mean I don't use mocks, but do often I find that mocks really do strongly couple your test code to your implementation you're testing. For example most mocks will mock out the specific calls that are expected in the path being tested, but this means that if your code implementation changes in methods it calls, their order, etc... then your test can fail even if it is still valid in what it's trying to assert. Over time I've seen this becoming more and more of an anti-pattern and have been trying to really focus on testing only the inputs and outputs of a method, and one of the easiest ways to do that is to have a very simplistic stub instead of a mock for more complex interfaces. You could do the same with a mock, but then you're mocking out implementations of all the methods, managing it with local state, etc... at which point you lose a lot of the benefits that mocking provides (namely the simplicity of it). The above all being said, I do still use mocks occasionally, but typically reserve them for single method interfaces or other such simple cases.
@twiksify2 ай бұрын
In fact, build your own mocking framework and you'll be amazed at how cleverly designated they are.
@nickchapsas2 ай бұрын
I have 😃
@antonmartyniuk2 ай бұрын
Stop writing your tests, save time to introduce new bugs 😅
@sanglin93872 ай бұрын
the only way to save your job is to create the bugs and when junior come , this simple cannot solve meh
@EdKolis2 ай бұрын
I've still got a GitHub page for a milestone out there that says, "Adding lots of features and bugs in this version. I mean, fixing bugs! Fixing them!" 😂
@pedrosilva14372 ай бұрын
There is definitely bad mocking behavior in many people's tests... just not in the example that person used. Where I see it go awry is when people mock everything to isolate one single class or method to test. It's best just to mock the services that interact with external sources (DBs, web APIs, etc)... not mock the classes in your call hierarchy and project.
@sasukesarutobi38622 ай бұрын
Definitely this, especially because this is one of the ways that lead to tests that only test the mocks and not the actual SUT.
@TheOceanLoader2 ай бұрын
Just because you can do something, does not mean you should. Fakes are an alternative test harness used normally to expose protected members that mocks cannot.
@minhhieugma2 ай бұрын
I think the author meant the UserStoreFake expose the Users property while it isn't there in the interface. It makes sense I think
@maximebeauchemin21002 ай бұрын
My favorite pattern is dedicating a directory in test projects for shareable mocks that can be reused across different tests to mock out standard behavior. Then have multiple separate constructors for those that can have it behave in different ways, or even have ids being passed in as parameters if you want targeted functionality by ID These return the Mock itself, so you can still override things even beyond the base before running your test
@trevorprice24902 ай бұрын
Prefer fakes when possible, but sometimes mocks are far superior
@Peter-fs4ds2 ай бұрын
The UserStoreFake won't need custom logic for every test since it's not the class being unit tested. It would simply add a user to the list and then retrieve it during the get, like in your code. Each unit test shouldn't need bespoke logic in the UserStoreFake - the example is only concerned about logic in UserService. So even if UserService has a ton of logic and needs 50 unit tests, those should all be covered by the basic implementation of UserStoreFake that you showed. If UserStoreFake does need complex logic to handle all the tests then that would also be an issue when mocking and would be an indication that UserService and UserStore shouldn't really be tested separately from each other anyway.
@classawarrior2 ай бұрын
Exactly - the point is that UserStoreFake fulfills all of the obligations of the IUserStore interface, and so any code you're testing which depends on IUserStore should work alongside it. And if it doesn't, that means there's a bug with that code.
@teothe2 ай бұрын
There is a notion that says that all business/domain logic be implemented in classes without any external dependencies. So even with internal dependencies, eg domainClassA needs domainClassB, you don't use mocks and those tests are still unit tests. Also this notion says that any external dependecies should be handled in integration tests, not unit tests, which will not need mocking. But this notion is not mentioned in the post you mention, so, still bad advice. But that notion, although it might be difficult to implement, is kind of interesting to see in practice.
@dvanrooyen14342 ай бұрын
You are better served to use the correct tool for the job, understand when to use a mock and when to use a stub, then when enlightened you can make the decision.
@chriswelles12 ай бұрын
Fakes make for much better tests. They provide much better support for refactoring. You don't "add new code for each new test" as you suggest. The fake gets shared. Part of the confusion here is that you're probably writing your tests for one method at a time. Much better to write sociable unit tests rather than the more simplistic isolated ones. Isolated unit tests are great for little complexity bombs things like regex expressions, some date logic, etc. but otherwise they're like pouring concrete around your code to set it in place.
@user-tk2jy8xr8b2 ай бұрын
Some things cannot be expressed in Moq, like (pseudo-syntax with type lambdas) `.Setup(m => => m.SomeMethod(It.IsAny()))`, but are expressible via stubs. If someone is bothered by the repeating `.Setup(...).Returns(...)` in tests again and again - they can extract it into methods `MockMethod1(this Mock ...)` or extract the mock expression into a variable because it's just an `Expression`. One disadvantage of mocks is their dynamic behavior, `Returns` with an incompatible result type won't fail in compile time, unlike a stub method.
@qj0n2 ай бұрын
That's a problem with Moq, not mocking in general. NSubstitute requires Return() method to take type compatible with type of mocked method (and optionally it can wrap it in Task). Never understood all the mocking frameworks with Setup method, felt overcomplicated
@user-tk2jy8xr8b2 ай бұрын
@@qj0n mocking in general doesn't support open generics, it's not expressible in C#/.Net (except `typeof`). Will NSubstitute's Return fail in compile time on type mismatch?
@qj0n2 ай бұрын
@@user-tk2jy8xr8b yeah, in NSubstitute you don't use normally a setup method so it's object.MockedMethod(input).Returns(returnValue). This way, Returns method is just a normal generic ensuring that what it takes is what MockedMethod returns
@lldadb664Ай бұрын
I've inherited some test abstractions each prefixed with "Mock" that are really Fakes but are implemented using Moq.
@manasmangalpattanaik35392 ай бұрын
Mock creates custom implementation dynamically for the mocked interface while executing the test cases, which is pretty heavy. Using fake is straightforward.
@gnsarkar68602 ай бұрын
I have been using fakes since the beginning more than mocks. For some reason I always wondered people using mocks are super smart and cheating in writing unit test just for the sake of achieving the code coverage. Glad to see that there are other people also who have the same understanding.
@davidmorgan11902 ай бұрын
I think he may have a point about the multiplicity of mocks that have their own assumptions about how the dependency works, how this leads to duplication and makes things harder to change. Rather than writing fakes, lately I've been thinking that I should be making a mock builder class that goes with a dependency so it can be set up in a repeatable and configurable way for different tests.
@EdKolis2 ай бұрын
That sounds like a mocking library. Why reinvent the wheel?
@liva236muzika2 ай бұрын
I did notice a sharp drop in the number of mocks I use. Since a lot of the code I write is CRUDish, there is not a lot to unit test. Plus we use DbContext directly. So in response I just do integration tests on the entire API using WebApplicationFactory and TestContainers. If I had a more domain logic heavy application, then I would move logic to Aggregate Roots and unit test those. So it would still result in not having a lot of mocks.
@bartholomewtott38122 ай бұрын
If your test expects a method on a mock to be called then yes indeed your test is coupled to the implementation.
@alexeykostylev39982 ай бұрын
implementation of a mock?
@bartholomewtott38122 ай бұрын
@@alexeykostylev3998 no the implementation of what is being tested
@alexeykostylev39982 ай бұрын
@@bartholomewtott3812 tested? Method invocation is being tested, not the implementation
@bartholomewtott38122 ай бұрын
@@alexeykostylev3998 yes that's what mocking is about. The test asserts on how the method being tested invokes the mocked dependencies. (Interaction testing)
@qj0n2 ай бұрын
Not really, calls from tested function can be also considered part of its contract. E.g. You can mock Mediator and check if method emitted event. You can test if the method sent an email, by checking out on a mock of email library. You can test if method pushed some data via http on a mock of http client If the purpose of thr function is to modify the state of other class or system, you can check if that happened by asserting mocks. The only check of such calls is unnecessary is when you assert calling query methods
@deezleguy2 ай бұрын
These days, when the data in question comes from a database, more often than not I rely on a local database than a mock using things like test containers and respawn. Does that make it an integration test instead of a unit test? Yeah probably. Don’t care. I’m testing more of my code using something closer to production, without adding flakiness, and a change that breaks many tests tends to be easier to fix in the test data than fixing a bunch of mocks. I do think mocks still have a place but I find integration often tests cover more ground and achieve similar end goals.
@gileee2 ай бұрын
If no one mentions testing on a project I just do some quick integration tests with, exactly as you said, test containers and don't lose any sleep over it.
@gppsoftware2 ай бұрын
This is a good point. I think the problem is that a lot of people have difficulty in working out what should be a unit test and what should be an integration test and consequently, there is crossover between the two with unit tests coding for scenarios which an integration test should cover. Ultimately, integration tests will test an entire system, so a radical thought is that unit tests may not actually be required at all... Local databases are a good approach, but there is also 'memory databases' which don't need rolling back!
@gileee2 ай бұрын
@@gppsoftware I just default to integration tests unless I'm expecting them to take 2 days to execute.
@pascalrunde912 ай бұрын
Please make a video about things people mock in your workshops which shouldn't be mocked! Thank you, your content is so great and I am learning so much with it!
@MiReiGi1984Ай бұрын
The tests as shown in the video don't even need the setup of FindById on the UserStoreMock. At no point does the Activate method on the UserService actually make use of FindById. Really the bigger issue here is that there's a service taking an input (in this case a User . . what?), presumably to find a User, modify it, and then persist it. That's bad design in general. What should be done instead is to find the User before the call to the service is made. The service itself can manage persisting the modified User, that's fine, but it shouldn't be responsible for finding it too. That leads to too tight coupling.
@wknight81112 ай бұрын
From the first example, the code with fakes is clearly less cluttered and more readable than the code with mocks. The author left a lot of details out of the test to make his point about cleanness and readability, and I think the point was made well. I don't like Mocks. Most classes should be testable without mocks if they are designed well, and the few classes which really require them (orchestrators like domain services and controllers, etc) really benefit more from integration tests than unit tests. Consider making most of your methods and classes pure, pull your interactions between classes up into orchestrators where possible, and hit your orchestrators with integration tests (gives your DI a good workout too!).
@jonathansocol2 ай бұрын
Sometimes, when I see this kind of advice around Reddit, StackOverflow or anywhere else, I get the feeling they're just trolling us. The worst part of the story is that, in the past, I had people angrily coming to me and using these trolling posts as "supporting documentation" for their ideas, discrediting mine at the same time. Beautiful.
@SlowAside52 ай бұрын
I think the post would have been better received if the tip was entitled “Consider in-memory repositories” “Avoid mocks” comes across as too dogmatic. Having said that, I have an issue with the point Nick raised at 9:50. I wouldn’t put all that extra logic in the in-memory repository. That would go in your service. The repository would have very simple CRUD operations.
@Le0Amv2 ай бұрын
I just heard what you said about the mappers do do not mock them. I thing we can mock them and then write separate test for those mappings, basically it will cover the mappings and when the map is update and changed you know what test is failing and why. What do you think about this? I was working in a project were we did not mock the mapper but injected the same mapper we used, but i feel this does not follow the true essence of testing and it can allow errors, when the source of truth should be the test in TDD. Thanks for your awesome work, continue fellow Greek "fan" here.
@batressc2 ай бұрын
Use mocks for unit test and testcontainers for integration test. I belive fakes it's a alternative for beginner developers but it's neccessary to learn how to construct the standard unit test to grown in the IT world...
@xlerb22862 ай бұрын
Yeah, I'm with Nick on this one (as usual). I've written my own fakes sometimes when I needed behavior that wasn't available in mocking libraries at the time. But I never did it because I felt there was anything bad about using a mocking library.
@luizadolphs60842 ай бұрын
Unit tests need to have a purpose... if you reach that purpose with mocks, that's good. if not, use fake. if not, review your unit tests, they may be integration tests
@qj0n2 ай бұрын
I've never seen the case when swapping mock to fake would add a purpose to the test. If the test scenario is pointless, it will be pointless with other dev techniques as well
@quicoll14Ай бұрын
Why would you need to have differential logic depending on the id? You could fake an in memory UserStore, so you do not need to make different things depending on the user id.
@franko56202 ай бұрын
I Totally agree with you , I mostly use fake implementation when a basic inMemory implementation of the dependancy do the job. For more hardcore stuff or specifics , i use NSubstitute
@robertmills81012 ай бұрын
If the user store already has an Entity Framework implementation, is it that bad to use it with in memory database instead of mocking it out? The EF implementation should be well testing reducing mocking and faking mistakes.
@condar152 ай бұрын
I think that the Users list was an artifact of the fake, and not actually part of the interface.
@ai-konkon2 ай бұрын
Yap, for me Moq still better than fake, as far as I understand fake is like 'stub' (or should I say fake is stub) in the same level you need to create an object to inherit the interface then create the instance of it, for you to simulate the method that you wanted to test. BUT yeah the same problem if you use stub for your method with have multiple behavior, you really need to create a condition inside of your stub class to the target test you need.
@tunawithmayo2 ай бұрын
If you have a lot of code inside a test, the thing that is being tested is too big. Break down the component under test into smaller parts, and the tests on the smaller parts becomes much simpler, and the mocks that they would depend on also become much simpler.
@sealsharp2 ай бұрын
Isn't this just kinda abstracting away the ugly into a different source file?
@Robert-yw5ms2 ай бұрын
I thought and hoped this would be about trying not to mock things that don't need mocking. But I should have known better.
@scodadude2 ай бұрын
I tend to disagree. I think mocking stubs is not a good approach, because mocked stubs couple your unit-tests to a specific implementation of your SUT. For example, if you set-up a mock to only return a user when FindById is called, what happens when you refactor the SUT to use a different look-up method instead? That test will break, even though nothing actually went wrong. The implementation was just changed a bit. However, if you were to fake that stub, and (this is important) make sure the fake obeys the rules of the abstraction (that it follows LSP), then that same test wouldn't break from the same refactoring. You would be free to change the implementation of the SUT, and to use GetById instead, without the test breaking.
@arztje2 ай бұрын
I have had to deal with teams telling me both are bad - even with external dependencies. They would prefer you setup actual endpoints for them to test in lower environments but don't realize how hard this is to sustain or scale since you are depending on a 3rd party to maintain a dev endpoint.
@AlexBroitman2 ай бұрын
How that adviser asserts invocations? What if I want to test a scenario, where the IUserStore service throws exception or returns errors? I need to make new implementations for each scenario? In many cases you don't need any setup for a mock. Finally - very bad advise. Mocks - are very good tool for testing.
@junior.santana2 ай бұрын
I was thinking about that and the only solutions I imagine would include adding methods/properties to the interface just for the sake of those testes which is even worse. Smh
@AmateurSpecialist2 ай бұрын
I saw this post last week. I almost spat out my tea when I saw it, especially with his claim that he helps you up your TDD game. It's bad enough ten years later, I'm still cleaning fakes out of my test case library (thanks, guy who maintained the app before me).
@MattLethargic2 ай бұрын
Avoid unit tests completely, use component tests and test the entire system. Unit tests will only solidify your code architecture and stop you from being able to refactor your code... If you do refactor it you have to change unit tests and then potentially lose the original intent of the tests and could introduce regression bugs
@iliyan-kulishev2 ай бұрын
The fact that one needs to mock or fake in a unit test is an indication that the method is doing both business logic and interaction with the external world (http, files, db etc.). Unit tests should be strictly business, but because of poor separation of concerns one needs some kind of test duplicate for the dependencies that interact with the external world. These two concerns should be separate.
@StuartQuinn2 ай бұрын
Agreed. I tend to give the advice not to avoid mocks, but to avoid designs where mocks are needed to unit test the behaviour of the class. Favour refactoring business logic into pure functions where practical.
@Mattitude2412 ай бұрын
Nothing is ever a one size fits all. I can see why you would use fakes, its a simple way to descibe a specific test. I agree with Nick though, you start to house logic inside your fake and that could easily run away when you work with various people, various teams etc. One thing I like about Mocking is its generally designed as a framework. A framework aids in a practice and approach. I can see fakes could become a bit of a free for all amongst a larger team over time, people appending to a method some condition to give me my expected result. Thats not too say a mocking framework cannot be abused just as much. I think overall, theres a time and place for each. I enjoy the mocking library with the setups and verifies. I dont see it being a bad thing to tie expected method calls in a test for example... Its part of my expectation of that test. At the end of the day, you achieve the same goal, does this method do what i expect.
@chisinusx71052 ай бұрын
Use "?" instead of "!" in your video title. I have watched many of your videos. They are great! This is the one I was attracted by the title 🙂
@innerbytes2 ай бұрын
If it's a unit test, you should mock every dependency of this class or function. Test the class or function logic only. Otherwise it's not a unit test anymore.
@mouayadkhashfeh49672 ай бұрын
Read about Test doubles, mock in not good for all the cases, and that if else you added to fake is not how the correct way to fake services
@Mio2k102 ай бұрын
I like the series. Thanks for debunking all of those statements :)
@TheScriptPunk2 ай бұрын
What happened to using the services that make up your service pipeline for a given test? You would already have made tests for it in the first place to not need to rebuild a mock from scratch. The only thing I mock is data
@wladdovy43702 ай бұрын
In general, there is a whole classification of test doubles. There are fakes, stubs, mocks, dummies, spies - each subtype of test doubles has its own area of application. The author probably wanted to say that for the situation when we are making a simplified simulation of a repository, we need to use a fake (according to its definition) rather than mocks. However, this approach is out of touch with reality, like my school professor, who does not write code in production, but gives lectures to students. Sometimes, by misunderstanding, such people come across a technical interview and you leave it with exactly the same expression on your face as Nick in this video :)
@alejandroguardiola90852 ай бұрын
I personally prefer to use a fake that I can reuse In all of the tests in this case. I don't see why you would need to write custom logic in the fake tbh, if the interface is implemented as a valid IUserStore I don't think that custom logic is needed in the fake.
@gppsoftware2 ай бұрын
I have seen a lot of people configure mock setup to the extent that they override all the methods for various tests. They don't realise that they have actually created a fake and just used a mock framework to do it!
@allinvanguard2 ай бұрын
I don't really agree with this.. Writing your own fakes is bad, of course. But mocking does couple you to the implementation big time. In an ideal scenario, mock unmanaged third party dependencies. For integration tests, use a test container and mock as little as possible. Both options, mocks or fakes, in unit tests, are not something you should strive for. A unit test should ideally test logic so pure, it does not have to interact with databases. If your app has very little of these interactions, then it is a good sign that your app just has very little unit testable logic and you might prefer a testing diamond with a focus on integration tests over a test pyramid with useless unit tests. Relying on mocks and verifies makes your test extremely brittle when it comes to refactorings.
@kevinlloyd95072 ай бұрын
So I was going to make the point that List Users doesn't look like it's on the interface, probably it only exists on the "Fake" (of the code they didn't provide)...but then there's still all the rest of the stuff LOL
@All-in-on-GME2 ай бұрын
One thing is clear--- no one in the comments fully agrees with the other's take on mocks, fakes, and tests
@wmel942 ай бұрын
I disagree!
@dominiquesavoie5682 ай бұрын
I find the Mocking libraries to be fine. I also do not understand the comment on coupling. It's a library using interfaces to generate a mocked equivalent of a service to return predictable data in order to test a call of the actual tested class.
@Timelog882 ай бұрын
I would say there is a reason we generally try to abstract away dependencies on 3rd party services and/or frameworks, in our code; to make it easier to change. So why do we happily couple ALL our tests to a 3rd party service in the form of a mocking framework? If the Moq debacle showed anything then imo it is we should use the same approach to our test code as to our production code, limit the coupling. Does that mean you should not use mocking frameworks? No, but it does mean it might be a good idea to abstract them away from our tests, in which case it's often easier to just not use them.
@DxCKnew2 ай бұрын
Our codebase is polluted with mocks, like at-least 20-30 mocks per test, something really difficult to manage long term. I am an advocate to write unit-tests that are running on 99% real code in-memory system, except for very slow or external parts like DB or other IO gets mocked/faked.
@macgyverx832 ай бұрын
20-30 mocks means 20-30 dependencies that need to be managed. For my taste this is kind of a big code smell that needs refactoring and some thoughts put into the design on the production code and not on the test. But I also know the rule "Never touch a running system...". I would extend it with "without exactly knowing what it does...".
@pzodeosrs2 ай бұрын
@@macgyverx83 Agreed. 20-30 dependencies sounds like bad code structure. Hell, even 10 sounds like a lot. Most of the code I currently work with doesn't go deeper than having 4 dependencies that require mocking when testing.
@Timelog882 ай бұрын
@@macgyverx83 "20-30 mocks means 20-30 dependencies that need to be managed. " Or it means 20-30 tests each with their own setup that is the same for N+ tests across multiple test classes, which is see A LOT in mock heavy code bases. In that case a single shared Dummy, Stub, Spy or god forbid, Fake can be better. But, this seems to be mostly a problem with test suites that make heavy use of mocking libraries and less with test suites that use self-written Mocks. (edit: I read test "suite" in the OP for some reason, not just test, needing 20-30 mocks for a single test would not be a code smell, but a hard merge request reject for me)
@pzodeosrs2 ай бұрын
@@Timelog88 They said 20-30 per test
@Timelog882 ай бұрын
It doesn't make sense to use either a mock or a fake in this case as the we don't need a complicated working version of the store nor are we testing something specific to the interaction between the service and the store. In this case a simple stub would've sufficed and any test that just needs a stub could reuse that stub. edit: Looking at the interface of the store, you don't even need a stub, a dummy would suffice as the Store method returns void.
@AndersReinhardtHansen2 ай бұрын
Doesn't the UserService change the state of IsActive? Looks to me like it does.....
@Timelog882 ай бұрын
@@AndersReinhardtHansen The service does yeah, and the nice thing about OOP is that you can observe that change by looking at the reference of User, you don't need the store for that. A simple example without most setup would be this: [Fact] public void Should_activate_user() { var user = CreateUser(); var service = CreateUserService(); service.Activate(user); user.Active.Should().BeTrue(); }
@Timelog882 ай бұрын
@@AndersReinhardtHansen 🤔Seems I can't add code examples as my earlier comment was removed. The UserService indeed changes the state of the Users IsActive flag, not of the store. To observe the state of the User, all we need to do is check the for the state change on the user object itself; so we don't need a store to test the expected behavior. Now, if we assume that the state of user is never changed, but instead a new object is created with the state and then saved to the database (so user is not the entity) then we would need to retrieve it and thus use a more complex version of the store, however in that case I would use a real database and thus write an integration test. But looking at the fact that the original sample just overrides the user reference from store we can see the User is the entity.
@AndersReinhardtHansen2 ай бұрын
@@Timelog88 well we need to test that the value is changed, and for this you are correct as it is passed by reference, but we also need to make sure that the Store is updated with the object that we send, thus we need to verify that the userstore abstraction, provided to the userservice has been called. This is most easily done with a mock/substitute. We dont need a database for it. We just need to verify that the referenced object is passed to the abstraction.
@Timelog882 ай бұрын
@@AndersReinhardtHansen "but we also need to make sure that the Store is updated with the object that we send, thus we need to verify that the userstore abstraction, provided to the userservice has been called" No we don't, not is this testcase at least. Just write an integration test to make sure you can save stuff, no need to add all that extra stuff to your unit tests. But that is always the problem with these terrible examples, they are so simple it just doesn't make sense to use it as an example.
@dannycyberwalker2 ай бұрын
I thought the point was about not writing tests with mocks if your code contains a lot of dependencies and side effects.
@deyanvp2 ай бұрын
I think you did not mention the main problem with mocks, namely that they are a liability because they assume what the real impl would do. If you mock you have to be dilligent enough to add CDCT tests to the called/mocked code (e.g. in the context of mocking calls to other microservices) ...
@nickchapsas2 ай бұрын
This is only true for bad usage of mocks. If you use mocks correctly you have no such problems
@deyanvp2 ай бұрын
@@nickchapsas what do you mean? Why would the usage of mocks be bad when you have svc1 -> svc2 and you want to mock svc2 in the tests of svc1?
@MrWuffels2 ай бұрын
@@deyanvp Mocks shouldn't simulate what their real implementation is doing. They should deliver set values. Unit tests are for your business logic. All you need to know is, if your business logic passes the correct values to external dependencies, and acts correctly when it gets values by those dependencies. Any simulation of their behaviour is none of your business (logic)
@deyanvp2 ай бұрын
@@MrWuffels I was referring to values in - values out, sorry for the misunderstanding. But this is exactly the problem - the assumption that 1+1 results in 2 is something that you encode in the mock, but you cant be sure 2 will come out from the mocked dependency, maybe the real impl starts returning 3 one day, but you do not know and your test is still green. This is what I meant by liability, and that by mocking you are excluding code from the test, so you have to compensate that with CDCT on the other side. This was not mentioned..
@shooreshgolzari38852 ай бұрын
So you mock an output of 3 and handle what happens in that case too.
@GoodGod22 ай бұрын
I'll find this post in Internet and I'll like it.
@hellowill2 ай бұрын
Never mock means you still mock databases and 3rd parties. It just means you dont mock other services (i.e. your business logic).
@nickchapsas2 ай бұрын
Not what the author of the post said
@rfphill2 ай бұрын
All these years later, this with the fakes and stubs. Is there any decent books written in the last few years that put all this shit to bed? It's bad enough that I finally got my new shop to commit to coding practices that can lead to code that can actually be unit tested but I have to now give guidance on the swirling debates on mocks vs fakes. Sorry, just ranting.
@mysteriouse58912 ай бұрын
"I think we should all use Bakes because they are way better, and who wants to use a mock or a fake - that's so dumb!" Stick with Mocks. Nothing's perfect, but they win on flexibility.
@Mr7672672 ай бұрын
The LinkedIn post may been misinterpreted or poorly illustrated. Many integration scenarios will be better handled with fakes than mocks.
@brandonpearman92182 ай бұрын
Fakes are great. if you havnt used them before, give it an honest try. Nick clearly has no experience with fakes. I think I can explain the "coupling to implementation" part, Mocks need to be aware of very specific calls and you may even verify that a specific method was called, therefore you have coupled to the implementation of the method. With fakes you can just verify the result of the test regardless of how it reached that state. With fakes you are testing the result of the test and not the implementation of the method. This means that unit tests are still valid after refactoring a method. Fakes require more upfront work but save huge amounts of time on refactoring. FYI the upfront work is near nothing with AI.
@nickchapsas2 ай бұрын
Sure they are fine and they work for me for around 5% of my use cases but to say that it’s a "clean code tip" to replace ALL of your mocking with fakes then you’re clearly clueless and that’s what I’m criticising
@brandonpearman92182 ай бұрын
@@nickchapsassure the wording "clean code tip" is a bit weird but you 100% can replace ALL your mocks with fakes. I would suggest it for anything with significant complexity. Mocks are ok for simple stuff or code that has very low chance of change. "5% of my use cases" give me an example of where it works and where it doesnt. I agree those tests are not perfect, but I assume its just a made up example. Even in that example the mock is coupled to the Store method which needs to be verified. Where the fake has no reference to Store(), it just checks the result. This means when you have complex code that changes regularly you dont need to fix your tests. Your tests are more reliable. There are also other advantages with fakes but its a whole topic.
@qj0n2 ай бұрын
I don't agree. Own Fakes require dev to implement all methods of the particular interface. So when refactoring they increase a work to do - every change of method signature has to be reflected in fakes as well. I remember even the case when I broke the pipeline build when I added a new fake, some other dev added new method, both our branches built OK, but after merging they failed When using mocks, you just mock one require method and the rest can be changed as you please. That decreases the cost of refactoring
@brandonpearman92182 ай бұрын
@@qj0nmight be doing something wrong, it should take less than 5 min to add a new fake method. And sure any code can conflict with team, thats where CI comes in. I have seen devs take a full day trying to mock something because of the complexity. Fakes never have that complexity, sure there is more to write but is significantly less complex, which means less thinking required making it very very fast to write.
@qj0n2 ай бұрын
@@brandonpearman9218 sure there are more complex cases, but if majority of your test doubles are complex to write, I believe the problem is not with them. Most of test doubles in my experience are stuff like 'when asking for user with id 123, give X' and mocking libraries are the easiest to use and maintain there. Personally, I started to use more mocks when I switched from old, unnecessarily complex libs like moq and rhinomock to NSubstitute as it's simple to use enough to be better than Fakes in some 95% cases. And in 5% I still use fakes
@amin29a392 ай бұрын
what test?
@NickAskew2 ай бұрын
That is some strange advice, to replace mocks with implementations. Now I will admit I've needed to use concrete implementations of interfaces sometimes, but that's not to say every test should be done with implementations or that every test should be a mock.
@TheSysmat2 ай бұрын
Mocks are great to simulate dependencies
@oleksii7662 ай бұрын
This particular example is a good candidate for integration tests instead of unit
@DavidZidar2 ай бұрын
The biggest problem with mocks is that they are not reusable, you have to set up custom mocks for every single test which can get pretty awful. I like to use reusable fakes where it makes sense to reduce noisy recurring test setups.
@_tonypacheco2 ай бұрын
Not necessarily, I often put some basic reusable stuff into the mocks in the test class constructor (xunit). You can then override them if you need to in the individual test methods.
@DavidZidar2 ай бұрын
@@_tonypacheco But what if you have several different test classes that all need to mock the same service in a similar way? That's when fakes can be more useful imo.
@Timelog882 ай бұрын
@@DavidZidar Just implement the mock yourself instead of relying on some mocking framework and you can easily share it. If there is one thing Moq has but nSubstitute lacks is an easy way to set up separate mock classes, but in general implementing a mock yourself isn't exactly hard.
@Kitulous2 ай бұрын
@@DavidZidar you make a static class with a method that sets up your mock and returns it. the way I see it a mock is just a fake that has a dynamic implementation, meaning you don't create a class yourself and don't stub all the necessary methods/properties, the mocking library does it for you. plus it can provide some useful logic like doing something each time a method is called or verifying calls, which is possible when you write your own fake, but it is more cumbersome to write than to simply call a method on a mock object.
@DavidZidar2 ай бұрын
@@Kitulous For a reusable mock you need to set up all methods anyway so at that point you might as well implement a proper fake instead.
@Rick1045472 ай бұрын
While the code provided is just bad and the advice lacking context fakes are a viable pattern to use if there's a way to write a very simplified implementation of the real thing in a generic way. I can get why it is claimed there is less coupling because you simply end up with less references to your code compared to mocks. Again context is king. However with this kind of code a integration test might be a better fit since it seems to be mostly about some simple CRUD operation. The query itself might even be the most complex part here...
@DisturbedNeo2 ай бұрын
10x Dev: "What's this? Mocking of unit tests? How queer. I should inquire as to the inner workings of this library to best understand how and when to use it post-haste". Average Dev: "Guess we mocking tests now"
@erynmacdonald2 ай бұрын
I don't know who posted that, but I'm willing to bet it was written by a SDET. Knowledge can be spotty by people who make this their primary focus or who have moved from traditional manual testing roles
@marcusmajarra2 ай бұрын
That was indeed a terrible usage of fakes. I think that the biggest argument I can make for mocks over fakes is that fakes hide information that is relevant within the scope of a test. With mocks, every relevant interaction with a dependency is programmed right into the test, which in turn informs developers as to what is relevant to a unit of code that is being tested. With a fake used like in the post, you have to ask yourself just how much logic is programmed into the fake, whether any or all of it is actually relevant to the unit of code being tested, and you run the risk of seeing that very fake being reused in different tests, which introduces further ambiguity as to what is relevant to a test. I find fakes to be more relevant when you're substituting an entire external system, such as a database connection. And, even in this context, I would have the fake be as close in essence to what I would use for production. But, at this point, I'm no longer testing a unit of code as I am testing the integration of my SW with its external collaborators.
@TheOceanLoader2 ай бұрын
This is ridiculous whoever says "don't use mocks" and demonstrates how they are I suspect, self-taught in the area of TDD with little real-world experience IMHO. I've been testing for 12 years and developing for 20+.
@bouboul35972 ай бұрын
To me, use fakes to check compilation. Don't write unit tests with fakes.
@Z3rgatul2 ай бұрын
"too much coupling to implementation" i think he means to mock libary implementation If you want to switch library you will have to throw away all mocking code
@Rein______2 ай бұрын
It's the implementation of the thing you are testing. In the test you are spelling out how some implementation details should work. By doing so the test is coupled to the implementation and must be kept in sync when said implementation details should change.
@Z3rgatul2 ай бұрын
@@Rein______ but there's no difference between mocks and fakes here
@bartholomewtott38122 ай бұрын
Nope. If your test expects a method on a mock to be called then the test is coupled to the implementation.
@ChristianHowell2 ай бұрын
Many of these tips seem to get around the way enterprise dev works... Even bad setups have a DEV database than can be used for full testing without mocking...
@themiwi2 ай бұрын
I knew this video was coming when I saw THAT post on LinkedIn 😂
@nickchapsas2 ай бұрын
At least 10 people sent it to me
@justinthiede89122 ай бұрын
Great that you made a video about this. I saw this on linkedin and commented that this was horribe advice. And this guy sells courses...
@MaximilianDeister2 ай бұрын
This post was a nice thing to find coming back from vacations, Nick! 😂
@Rein______2 ай бұрын
I dont want to change the tests if i change implementation details. So mocks are out, because you need to keep them in sync with implementation details. I do this for behavior tests at the level of MediatR handlers, so a bit bigger than individual methods or classes. I find it easy to make 'test doubles' that behave like implementations, i write it once and use it in many tests, only one thing to maintain vs many different tests. For unit tests i like pure functions that only depend on their input... so no mocks are needed.
@heliobessonirodrigues66322 ай бұрын
The thing that people don't get is: we don't unit-test boundary classes, only the domain classes. When I see a unit test trying to mock a http client or a db query/result I know it is there only for coverage, it doesn't test anything. And some classes are private/sealed, unit test is not possible in most cases.
@AndersReinhardtHansen2 ай бұрын
most cases? That is a bold statement. Unit test are great for testing business logic, and if your business logic only dependens on abstractions, then you dont mock http clients, you only mock the Interface which imeplements the logic which uses the http client.
@heliobessonirodrigues66322 ай бұрын
@@AndersReinhardtHansen Correct, that is how we isolate the boundaries, with interfaces. Boundaries are tested in interactive or E2E tests. Mocking HTTP or DB clients doesn't catch any error. If your SQL query has a typo, or someone changes the HTTP URL, or renames a table in the DB, your unit tests will keep passing, but your app will fail at runtime.
@AndersReinhardtHansen2 ай бұрын
@@heliobessonirodrigues6632 yup. I really like the test containers project, which spins up whatever databases or systems you want.
@binarybang2 ай бұрын
@@heliobessonirodrigues6632 So, you're aware of those cases and still argue that instead of writing unit tests where mocks mock that erratic behavior we need to ditch test altogether? That's just strange. The fact that exception-based control flow doesn't make handling those cases mandatory doesn't prevent you from testing the behavior of dependent services in those circumstances, just mock throwing an exception or whatever.
@heliobessonirodrigues66322 ай бұрын
@@binarybang Yes, how would you mock these erratic behaviors if the classes are sealed or have protected constructors? And even if the library allows it, it is not the real thing, you won't prevent regressions from reaching production. Only E2E tests will catch them, making these unit tests useless.
@frankroos11672 ай бұрын
I tend to sign my emails with "When all you've got is a Hammer, every Problem looks like a Nail". Looks like there are still a lot of people who like having just a hammer, instead of a whole box full of tools. Not realizing that a hammer is the wrong tool for a screw. Luckily, we have master Nick to point the way...except, the one-tool-minds probably don't watch this.
@Cesar-qi2jb2 ай бұрын
If you move your business rules into static methods, you no longer need a mocking framework. The main purpose of a unit test is to preserve the business. The rest can be tested by QA.
@MrMattberry12 ай бұрын
😂
@gppsoftware2 ай бұрын
@@MrMattberry1 I have seen some organisations write their code as static methods. And the resulting code is very painful to work on because the implementations I saw weren't open for extension and were difficult to override. My observation is that this style of programming comes from the React world where everything is just chaining functions together in an inflexible/unmaintainable manner.
@upgradeplans7772 ай бұрын
The LinkedIn example was all kinds of messed up. However, I do actually think that fakes should be the default choice unless there is a reason to use a mock. The reason for that is because they generally make the test easier to read and understand. (If at any point a mock or stub would make the test easier to understand, then the mock/stub should be used.) I'm not actually convinced fakes make the code shorter, but code length is always only an indicator of readability anyway, and not important in its own right. However, it doesn't help that the example (and also many of the comments here) seem to be unclear about what makes a mock different from a fake in the first place. The "UserStore" from the example is really just a hand-written mock, which is fine if you don't like the mocks a mocking library produces, but it doesn't show how or why a proper fake should be used. A fake should also always be written for exactly 1 unit test, and it should not actually implement anything. Even having the List in there is just too much. A good fake asserts that the passed in values are as expected, and returns hard-coded return values. Furthermore, all of this is actually specific to only isolated unit tests, which are not the only kind of unit test you need to write. (Although they should be common, especially if you write your tests first, as you should.) And it is also not a one-size-fits-all choice. There are a lot of considerations that may apply to your project that make it make sense to have a different default approach.
@gileee2 ай бұрын
Writing tests first is the worst way to write code
@upgradeplans7772 ай бұрын
@@gileee All other professions specify their validation procedure in detail before they actually build the thing. You'd be insane to use what you have already built as the template for creating a validation procedure. Code is different in many ways, but not about this. If you don't need the test before the code, why write the test at all?? Then for your next task, consider what tests you need to do a good job. If at that point you're worried that you're going to introduce regressions related the previous task, then go fix that problem by writing a test. At that point you're writing the tests first again.
@trevorprice24902 ай бұрын
Yeah this is my opinion too, after having changed opinions on this more than once 😂
@qj0n2 ай бұрын
Problem with Fakes is that it is coupled to signatures of all methods in the interface. Every time you change an interface, you need to change all Fakes Similarly, I have once broke build on master branch, when I added a fake and some dev added new method in the interface at the same time - simultanously built branches were ok, after merge they failed. Using mocks would prevent it
@gileee2 ай бұрын
@@upgradeplans777 I write tests so I can add/change/refactor behavior later without worrying if I broke something. They don't specify the validation procedure, they specify in detail all of the procedures that are part of the system. Which is how waterfall used to be done anyway. But it's not used anymore because it takes a lot of time for that QC even tho a simple company app or website doesn't benefit much from it. Still, even if you're writing code for a medical device, I'd still prefer that time being spent writing the documentation, not basic inputs and outputs.
@mbsa2202 ай бұрын
I heard bad advice from a good concept (like SOLID) all the times ! that's too SAD
@klocugh122 ай бұрын
A total mockery of advice there.
@I_am_who_I_am_who_I_am2 ай бұрын
Why is LinkedIn used for programming advice?
@kinsondigital2 ай бұрын
I am with you. That is horrible advice. Advice for people that are new to the development world, be careful what you read!!
@hodgenick2 ай бұрын
Nick, I am tired too.
@othmanekinanenw2 ай бұрын
It's crazy how much pushback the tech community has around fakes, and how poorly they are understood. The best example is how Nick thinks that the fake code would contain all the specific cases.
@Scott_Stone2 ай бұрын
Yep. I mainly use fakes in the places that I know are connected and use mocks for the dependencies that are not involved. As a result the tests do look bigger, but they require less maintenance and create less false positive alerts where it is the test itself that is broken, not the code underneath.
@nickchapsas2 ай бұрын
Because the alternative is to use .SetXXX methods which practically work the same as mocks, but with extra code. There are use cases but it’s less than 3%
@othmanekinanenw2 ай бұрын
@@nickchapsas If the interface is used in a single test class, then yes, you better use mocks. Otherwise you really have to ask yourself how to scale the mocking of that interface, how to be robust to refactoring, how to be sure that the many mocking of the same interface have a coherent behavior, ... Everything is a tradeoff. Personally I don't mind adding code if it makes the tests more readable and gave me a higher confidence in them.
@Rein______2 ай бұрын
I too find this crazy, fakes, or test doubles, are not hard to write or understand. Mocking code on the other hand... can become unreadable, unmaintainable, not refactor friendly...
@gppsoftware2 ай бұрын
Agreed. I thought the idea of SOLID principals, particularly the L, I and D parts were about the ability to replace components with others conforming to the same interface...in other words, it describes a use case of it: fakes.
@denis.akopyan2 ай бұрын
You've just mocked the person for asking not to mock 😂