Let's Get Defensive With Mocks - LET'S CODE LIVE!
I have some YouTube tutorials to make on several topics - so I'm going to live stream the creation process and explain more things in depth!
View Transcript
the right platforms and stuff going on so I'm going to be trying to create or go through some projects today for YouTube content actually so I figured I'd go through like a bit of behind the scenes as I'm creating this stuff and then you can see the thought process because one of the challenges when I'm creating content for YouTube is like I need to be able to explain scenarios and sometimes I have to program things in certain ways and then maybe refactor them or change them up to get a point across so I figured why not demonstrate that you'll see like the finished thing so you'll get like you'll kind of understand what's going into the YouTube video you get the technical details behind it and then you you can ask questions as I'm going and that kind of stuff unless of course you're watching
the recording and then you can't really ask the questions but that's okay um but yeah I'm just doing a quick check to make sure it's going to the right places it's saying my stream's bit rate is very low but also that I have a good connection so I don't really understand but I think we're okay so uh I'm going to switch over to visual studio the the first one that I'm going to walk through is about writing uh unit tests when it comes to situations where you're dealing with external services in particular around the error scenario so let me go ahead and switch over here uh it might drop my video for just a second yeah like my face isn't showing right now I don't know why it does this but here I am cool okay so here I am in Visual Studio this is
a solution that I have from a recent video I did it's still kind of early here so my voice is going um and what I was demonstrating in that video is different ways and different scenarios that you would leverage a try catch versus failing fast but how I ended that video was saying that I wanted to be able to demonstrate how we can go write tests on this type of thing and again different scenarios for different types of test coverage blah blah blah um so I'm going to end up adding a test project here but I want to kind of talk about this as I'm going through it so a little bit of multitasking which I need to practice talking and clicking through stuff but what I want to talk about in particular is putting unit tests in place when we need to be able
to mock out external services and I don't know why this isn't searching last Library there we go I'm using net uh oh my goodness a visual studio preview so um I updated my normal visual studio and the intellisense and auto complete went on me and then I was like oh no I don't know how to program anymore so um let's just call these unit tests Let's do let's get defensive I was trying to be creative with my naming but you know it's kind of tricky so we'll make that oh no why did it pick that framework version oh you know what not what I want oh man let's see this is what I get for using the preview version it made like a an old school project get that out of here okay give me one moment this is not starting off so hot where
is this really hopefully this works I got to pay attention this time okay and there we go net 8 I do have net 9 preview but I'm not leveraging anything from that so this is what I wanted to do amazing okay so now I'm going to be adding the dependencies into here uh these are going to be Nate packages that I like to use so I like using xunit I still use mock like moq so let's go up to browse type in xunit couple things we need to get so xunit itself We'll add that in I need the xunit runner for visual studio let's see get that I need the this one's a little weird um test SDK if I don't do this then Visual Studio doesn't seem to find anything and by the way because I'm on the preview I don't know if things
have changed or something like that so I'll probably find out the hard way which is great and what's the last thing I do mock I know a lot of people have moved away from mock but like I don't know I don't really care there was some drama that happened I don't know if it was last year the year before where the maintainer put something in and I don't even know all the details I think people were just getting kind of kind of wild about it but I still like to use it so okay now that we have this set up we should be able to very easily this is what was happening in my other Visual Studio it's making me nervous um some of the auto completing stuff isn't really working um although that seemed to go pretty well and look this is great um
thank you co-pilot it's kind of uh figuring out what I want to do here now I need to add in these dependencies and it can't see them so let's get this added in so these are uh two other dependencies right so the two projects that I had from the original video we'll make sure that we can get that stuff added in cool and we're going to have to make some adjustments here um so this is what I would call not a unit test and you might say well Nick it kind of looks like mostly a unit test to me like maybe I need an assertion or something but um the reason that this is not a unit test in the uh normal definition to me at least even though I'm testing one method I'm testing with real implementations of things so Nick's system in this
case would be what we refer to as the system under test because we have um the one method do the thing being exercised here for this test under the ACT part but what's what's not um helping with this unit test and I'm going to explain this in just a moment because this is just like a you know U semantics kind of thing but cool client is a real dependency so not only are we testing nx's system do the thing we're technically exercising cool client okay so if we just want to prove that do the thing is doing what we expect and we use a real uh implementation of this dependency like this is what we call an integration test or a system test right because we're testing these things working together and this could be a good test I'm not saying that this is wrong
right I'm saying that in my opinion this is not what I would call a unit test so hopefully that makes sense the way we change that though is I'm going to make a mock repository and my settings aren't carried over okay and then what I like to do maybe let's give this a better name um give that a name excellent and then I need to make a new mock repository so I like I always like explicitly having Constructors and apparently co-pilot knows that so um something important here mock Behavior strict okay so the strict part is going to ensure that when we are creating in mocks off of this mock repository that they are not what we call loose mocks and that means that if someone's calling a method on the mock it must be set up explicitly it's not just going to have a
dummy default behavior um some people lean into the you know the dummy default behavior of loose mocks uh sometimes you'll see this with loggers and things like that my opinion is like if you're writing a unit test by my definition of a unit test you need to be testing the things that you've set up and if you're not then it's not a unit test like you're kind of doing what would be a functional or integration test and like and and actually like ex you're basically saying I don't care what happens which to me is kind of weird some people don't for loggers but I generally create systems where I like to make sure if I have logging that it's working correctly so we have this mock repository instead of having cool client like this though I'm going to make it such that the mock repository
gives us the cool client and then that means down here we do this um now if we're writing a few tests sometimes what I will do and this is I going to do show you like a premature refactoring here but uh something I I like to do is uh kind of pull these things out up into here and that's because if I keep going to write test these are going to be two common lines that come up all of the time in every single one of these so then I would do this private read only I cool client right so this kind of thing would happen and actually I called it NYX system but let's do that okay so this goes into the why isn't that working oh this is the thing about live streaming it you'll see me make all my mistakes of course
not that I don't make mistakes on my normal videos but it's a little more obvious when it happens here so these The Constructor for um for xunit test is going to run before every single test that we have okay so that means if I go to have another test you know say we go to make test two or whatever blah blah blah um that means that we'll always get these recreated so that's something important to understand about xunit is that the Constructor runs before every test not just once globally for all the tests um and then also this is I didn't follow my my nameing convention properly maybe we should do that let's do the thing a sync by the way if you are wondering how I'm refactoring the name very quickly it's just F F2 in visual studio if I press f2 over what
I'm typing I can just do a rename and it goes and renames it in all the places right so you can see it's called do the thing async here already right um very nice also something important to note is I have an interface on this thing right oh no I don't on Nick system I don't on cool client I do but if you do a rename on a interface meth that it will do it in all the spots that implement it which is pretty cool okay so we need to await that right and then essentially now we have what would be like a unit test except we don't have assertions we don't have anything else going on so we have to build a little bit more code here now going back to what I said at the beginning of this stream what I want to
be able to focus on is making sure that we can have the client behavior that we expect and what I want to talk about in particular is throwing exceptions so it's funny I'm streaming this and I haven't fully thought out the example I want to walk through so you'll kind of see some of the thought process that goes into that and it's like it's too late to to bail on this because it's already live on the internet so I have to kind of figure this out going through it but um this login async method on the client if you haven't seen the previous video that I did on this that's on YouTube um you know the doc comment itself says only throws this exception but like it it's not true like that's the only one we explicitly throw but get a sync on this HTTP
client also throws real stuff okay so we're not documenting that up here you know it would be good if we did or if this method handled those exceptions directly and had its own dedicated you know exception that came up that's not how this is implemented though so the the thought process behind writing tests around this kind of stuff is like you have a couple of different I mean plenty of schools of thoughts I'm going to go back to full camera mode here so I can talk with my hands but of course the camera disappears when I do this there we go there I am um going to talk with my hands a little bit here so you'll have folks that you know I I literally saw this last night on LinkedIn before going to bed from people that I you know they're people that I
respect in the content they're posting but I just disagree with with what they're saying and that's okay we have different perspectives it's not everyone has to be the exact same way so the the claim was about mocks and you know overconfidence in mocks which I think can absolutely be a thing but they basically said only mock what you own and I I believe the rationale here is like when you create a mock you are in this position where you are you're you're kind of you're faking obviously what is you know the real dependency and because you need to be able to respond so you set up a mock and it needs to have a return value or some Behavior like you need to set up the mock such that it behaves the real way and I mean yes and no like you you don't have
to um it's in my opinion that's not the point of the the mock I see princess Pamela on Kick thank you for the the nodding cat Emoji that's great um the like a mock in my opinion if I were to kind of back up from how people are recommending to use them the reason that I like to use MO is that it gives me complete control over the execution flow inside of my class or method that's calling it and why that's important is that like if I'm writing other tests like integration tests I am trying to prove that real things work together real things work together and that's important because that's going to demonstrate how your real production system or as close as as possible to it works when it comes to mocks that's almost not what I'm doing at all which sounds funny when
I'm using mocks I'm trying to test that I have complete control over what's happening inside and here's the the situation I want to describe to people because um I think oh I'm showing my code now my goodness um this what happens when I live stream right so what what's what's challenging when you're dealing with integration tests in real systems like one of the situations is error handling so I want to I'm going to flip back to the code um and I want to talk about let's pretend and this is you know kind of the YouTube setup here that I'm I'm trying to get across is like I want to create a situation where I can say to you hey look you had a bug there were some exceptions being thrown you want to put some error hand in place prove to me it works prove
to me with a test that it works because that's new expected Behavior or maybe it was always expected and it there was no coverage against it prove to me it works and tell me you're going to and I would love you know either on if if it's on stream great I can put this into the real video when I make it but prove to me it works when your system your dependency throws an exception and you can you can work around it and I don't think that you're going to have a good time being able to do that unless you're mocking it and I say that because you don't control the third party or external dependency Bob James good morning good morning yes it's uh it's 6:50 in the morning here usually I live stream at night on Mondays but I figured it's a a
Wednesday day before work my my wife is uh traveling to go to a wedding right now and I said you know what it's time time to live stream but yeah um good morning yeah so the the point here is that I want to make sure that I can go write a test that gives me that comes back to confidence right I want to have confidence that I have the right aor handling in place it's time let's go that's right okay so let's go back to the code here again my face will probably drop off every time today it's us when I'm making YouTube videos this actually doesn't happen um I get pretty lucky so okay we're back in the code let's see by the way I'm coding on one quarter of my monitor so what you see on the screen on the stream right now
is one quar of my 48 inch monitor so I'm coding in a what feels like a very very small window to me but um okay hopefully the the font and everything's okay so this is the system that we're testing I might want to kind of clean up some of these because we don't need to worry about them so much so um I think what I'm going to do is I'm going to get rid of this public one because I want to just I want to focus on these for now um by the way like this isn't I'm not doing this as a refactor that I would say like hey look this is making it testable I'm doing this because for demonstration purposes it's not going to be necessary to to have the other code I just want to be able to come into here okay
so if we look at this kind of thing the due critical work part in the YouTube video that I made before does not need or does not want a try catch and it doesn't want that because it's supposed to fail early if it's critical work it's supposed to fail early in the nice to have work it's not awesome thanks for letting me know Bob James looks good okay if it's ever getting cut off or something's not showing please feel uh happy to jump in and just say what's going on so I got to get rid of this code up here now so let's say do nice to have work blah blah blah okay not really important we don't really care about the entry point to our program right now we care about the tests and you can see here that that's not all doesn't exist
here as well so okay in the original video that I created with this example we were saying when you're working with code that is I said like it's nice to have code that's executing that could mean that it's something that could be retried could be anything right so if it throws an exception we want to make sure that we can keep going so that means that it needs to have some type of TR catch logic in there okay so you can see that from the example here I put in like a specific error handling we don't need that to start with but I want to actually let's get rid of this whole thing right let's just make sure that we don't have a TR catch to start and we'll walk through this okay so the nice to have work and the do critical work are
starting off the same way and to be transparent when I was creating the other video this is how I set it up to start with so if we go back here right we're testing this method so we'll say uh that's the method we're calling um client so this is a terrible naming for now but I I haven't like I said I haven't fully thought out what I want to do here yet but we're going to call this method and what's going to happen is the client that we have is going to throw an exception okay so I want to say cool client we're going to set up the method get an exception thrown so let's talk about this kind of syntax as well we'll say throws I don't know what kind of exception I want to throw yet we could start with this one actually
this is going to be an interesting one I in the video I made before I said unauthorized access exception by the way when I was making my video I said assess exception instead of access exception probably like 100 times and as a result my editor had to go through and and you know correct all of it so um we'll do that for now just to kind of walk through this example so the name of this method is going to change I don't know what I want it to be yet I just want to kind of have something we can step through but I wanted to come back to this it has any type of thing going on here now earlier I was saying when we make mocks I like ensuring that I have mock behaviors strict in place because if it's loose you are basically
admitting that you don't care what happens and when I'm writing what I call a true unit test I very much care what happens this is at odds with what a lot of people will say they're like hey like unit test you don't want to be coupled to the implementation and I say for my unit tests I absolutely want it coupled to the implementation because that's exactly what I'm testing and I will write functional and integration tests otherwise it means that I generally don't write tons of tests that look like this if I can cover my things with integration tests but throwing exceptions is one situation in particular where when you're trying to use real systems you don't have control over they're going to throw exceptions an unauthorized access my goodness I can't say it unauthorized access exception is one that you probably can have control
over because you provide the wrong credentials but we'll see as we go through this that if we want to throw other types of exceptions we don't have control so log in async when we're using it is any this is another type of thing where you're saying I don't care what's being passed in so something that's important if we go to my implementation right it's expecting a very specific set of credentials very specific now this would be terrible in practice you don't want to hardcode your credentials into here but I mean let's go refa like this is maybe a good opportunity to refactor stuff this is like you're going to see a bunch of tangents on this when I public the YouTube video this will be a little bit more polished but like let's go let's walk through this okay we don't want this kind of
thing passed in or sorry hardcoded we don't want hardcoded because you never want to have that kind of stuff like in your in your git repository not good practice so how can we do that well we can have a configuration of some sort so let me go make a uh Nyx config it needs an i in front for the naming convention I want to have a username I want to have okay so you'll notice that I started with an interface this is out of habit and I'm going to instead make it not an interface because this is something that we don't need to mock out um some times like for transparency when I make configs like this usually I do make them interfaces because I will have an implementation that say loads from environment variables or loads from an i configuration for asp.net so I
genuinely have different implementations of them but in this case I don't so it's kind of silly to do this so what I might just do instead is do like just a record type so NY config will it do this automatically for me sorry I'm trying to see if it will refactor nice and automatically For Me Maybe not that easy okay co-pilot can probably figure it out though thank you co-pilot I love co-pilot it's not an ad for co-pilot by the way no one pays me to say co-pilot but it's sweet um there we go so this is going to be a record type cuz like I said I'm only going to have one implementation of this I don't need to mock what is basically a data transfer object to dto so keep it simple but you can see that I'm going to be passing in
a config here now which means up here NYX config again thanks co-pilot so we pass that in there and that means that we are going to use that down here okay so now we're not hardcoding in our credentials anywhere right if I search for Dev leader in here that's the only spot we have it so this is a sort of like dummy program again you wouldn't do this you would have your credentials loaded from a config file or something whatever kind of source you want but in the actual code that's being run we don't have it hardcoded okay so now we have have that we got to go fix it up here which means okay this is coming back to bite me a little bit um if we're passing the config in it means that at some point if I want to change the credentials
we can't do that uh we can't have it created in one spot so I'll leave it here for now and I'll kind of show you what's going on though um the point here is that this doesn't matter okay and actually what I said because we're writing test and I have full control it might not ever matter I can probably leave it just like this um what I was trying to get at is if we were using a real system to authenticate against I would need to be able to change the username and password the point is we never care and I'll I'll actually I'll prove it to you okay we can literally use guids every time we do this they probably don't actually want to ever do this I just want to make a point as we go through this together okay the point that
I'm getting across here is we will never actually care what the username and password are we don't need to and that was a huge tangent coming back to it do is any because I don't like doing this I want to make sure that we are truly passing in the right things here this should be NX config do username okay and then even the cancellation token we could absolutely do um we could say we're expecting that we could even if you cared some systems you end up chaining cancellation tokens and stuff together oops so maybe you you genuinely care which cancellation token you're dealing with okay so I'll do that so you can see that this this mock setup doesn't have it is any anywhere it literally car cares about every single thing that's passed into this so this is going to be the first example
I want to show you where this matters this is a huge tangent from what I was trying to show initially but I want to demonstrate that we can catch a real easy bug okay so if we go to run this it's going to throw an exception um let's just kind of start it off though we'll see where this takes us for now okay that took forever I don't know why right so it throws invalid credentials for user Dev leader so that means that our mock did exactly what we expect okay so we set it up to go throw an exception that's not so fancy what I want to show you instead is that let's put these back CU I want to show you why I test this way when I'm when I'm writing unit tests and I actually care what's being passed around okay so
if I do this and run it again it should do the exact same thing so it's not going to be too exciting right so our mock is still doing what it needs to do I'm going to go break the code though okay I'm going to break the code sorry not here I closed it ah okay I should have pulled this thing out into its own uh place by now but let's break this right so not the real username it's not anyone's password right and then we will pass in a uh even if we do this none of this is right okay and if I go run this again it's still going to call my mock as we expect and if it's not obvious What's Happening Here the mock is still doing exactly what it needs to do it's throwing an exception because the mock saying
hey I'm being called but it's being called with everything wrong all three of these parameters are not the right thing so I like doing this sorry the only reason that that continued is the cancellation token I'm using is a the default one cancellation token. none is the same as default but you'll see that I put these back instead of it as any string and now when I go to run this you're going to see an exception but it's going to say like your mock is wrong right so it's not running the mock it's telling us like your test is actually not set up correctly it says all invocations on the mock must have a corresponding setup and it tells us that we were here expecting the config username and password to be passed in and if I go back to the test Explorer we can
see it's telling us hey you didn't set it up for haaha and not anyone's password but we don't want that that's wrong it's literally telling us that our code is broken so it can help you catch bugs just like I did here it's telling us that we expect the parameters to come directly off of this thing oops oh no so we expect them to come directly off of this thing even though they're guids that we set up here the point is that we can literally prove with a mock that we expect the values of username and password off of this config to be passed in as parameters this is extremely powerful can help you catch all sorts of bugs and even if you had a nice integration test I could have left Dev leader and password hardcoded in there I could have and an integration
test would not catch that it wouldn't tell you that you're pulling them directly off of here this tells us especially using a goid like these are randomly generated every time it's never going to be the same it's telling us look it's coming directly off of this thing okay so a bit of a tangent okay so in this example right now we're throwing an unauthorized Act access exception do nice to have work with o is not supposed to throw an exception right it's nice to have although in the original YouTube video I made I said unauthorized access acception might be one where we do want it to fail and not retry or something like that so this is a bit of a unique situation I don't want to complete this test yet I want to come back to it okay there's a method to the madness
I'm like I said I'm trying to create the scenario that I can put into my YouTube video and again more transparency I do exercises like this um either explicitly I will go through a thought process like this just a little quicker because I'm not streaming it or I take examples from when I'm genuinely coding stuff on my own and I go oh like that's a like I caught myself doing something and I go hey that might be good to show other people Okay so so we're going to have to come up with another scenario here the point is I don't want it to be an unauthorized access exception I want to bring it back to something I said earlier from a LinkedIn comment again um not because I don't like the people in fact I very much do like the people that made this comment
I just disagree with it they said it only throw the exceptions for systems you have or you know for uh that's not even the right thing it's too early only mock things that you own and the point of all of this setup here was I was saying hey we need to pretend cool client is a third party thing that we don't own I want to demonstrate to you why I want to mock this thing that's the whole point of this so I like I said I think the reason they're saying that is like you need to be able to have full control over you know everything that it's doing it needs to be in your possession if it's some third party thing you don't know you can't you're G to have false confidence in it and I'm like yeah man like it's the wrong reason
you're using mocks incorrectly if you're trying to make them match exactly what the the behavior is like that's when you do need a functional test okay so this thing can throw all sorts of exceptions but it doesn't matter right when I hover over this you can see sorry there it is there's four exceptions that this can throw this thing itself can throw an unauthorized access exception you can and I think it's help if there's particular scenarios like this one that you want to protect against that you do but if we go back to um this code here sorry this nice to have work in the YouTube video I made I said look if this thing throws an exception we want it to be able to continue on that's the whole point okay so we need it to be able to continue on now for that
to happen there needs to be a try catch around here somewhere okay so if we go back here let's not throw an unauthorized access exception let's throw a different one and we we'll just say something oops I have caps lock on so something unexpected happened okay we're setting up our mock this same way it's going to go throw this exception when the mock is exercised now this is nice to have work so we should assume that it doesn't throw an exception it's nice to have right um what's missing and I should call this out too this is going to be kind of a weird thing to communicate on YouTube because people probably aren't going to like it but everyone always says like your tests need to have an assertion um I sort of agree I just think that when you're looking for the word explicitly
that says assert um that's not necessarily true um because I'm testing void methods I can't assert a result on a void method it doesn't exist but if I verify all of my mocks are set up and they're explicit mocks not loose ones explicit mocks with verify all on them this will tell me that every single thing I set up was called so that's my assertion is that every system that's inside of the method I'm calling is set up okay so from there what's next this one's going to throw an exception right if we go run this it's going to look the exact same except the message is going to be different this run what's going on here oh I picked the wrong one here we go right so it says Hey something unexpected happened and we go okay like it's not supposed to happen this
thing should continue on so giving this a name here it says some unexpected exception is thrown but the code path still completes again this isn't great name I just want to have something in place as we go through this but that's not what happens here right when I run this test the exception is getting thrown like we don't want that this is nice like this is a code path that we might want to be able to retry or something like that in fact I'm hoping we can get to retrying in here so no this is not okay this test is failing so how do we fix it but a try catch around it right this was going back to being defensive or not um and you could do a thing that's like you could do this um maybe I will talk about loggers I'm not
sure if I want to do that yet it might be kind of Overkill I'm just checking the time too uh um yeah maybe we can do a logger let me let me go through this example right first there's too many tangents you're kind of seeing how my my brain goes when I'm trying to put this stuff together ahead of time so I'm not catching all the exceptions I'm catching specifically this invalid operation one I want to kind of come back to why a lot of the time I do end up just putting this and catching all of them I mentioned it the YouTube video video but like we'll kind of maybe see it in a moment um okay so this test should hopefully pass now the assertion of verifying all why did that not work did I put it in the wrong spot oh yeah
I did my goodness ah okay sorry wrong method I told you that they were set up the exact same way that was bound to happen that's my fault this is the kind of thing when I'm making a YouTube video by the way um I would be sitting here probably pulling my hair out for like 15 minutes before I realized what happened so I'm feeling very good that I caught it early but now okay this test should pass right it's doing what it needs to do there is no speciic specific assertion aside from testing the mocks because it's a void method I can't assert the return value there isn't one but I am proving the fact that it got to here means that this did not throw exceptions and we called everything we wanted to set up now this test is also going to pass or
not right it's not going to because I'm only catching invalid operation exception so far so good okay now now you might say hey I want to test some other things again my naming here is not going to be good so um please bear with me um let's actually go to cool client what else can it throw uh HTTP request exception okay right if you were like hey I I genuinely want to write some tests against what this thing can throw by all means you could do something like this so we we'll say um right if there's an HTTP request exception maybe it's like an intermittent failure right it's transient you want to be able to have some retry stuff again hopefully we can get to that that go run these tests it fails right it fails because nothing's handling it so your options at this
point you can keep tacking on right you can keep doing this kind of thing but ultimately again going back to what I was saying in the YouTube video around this was like ultimately I find that that's not what I want okay so I want to make sure that this thing doesn't mess up right I don't want it to Brick the rest of my code so I generally end up doing this I know that's probably going to bother a lot of people but I like being defensive in this way and then looking for specific exceptions when there's a problem okay so going back to the test I actually want this one that's unauthorized to not continue on okay I want this one to fail everything because we're GNA I'm not I don't know if I want to use uh Paulie for this live I might just
kind of do a manual retry thing I want to show you that we can put some retry logic in and how that comes up but if your credentials are wrong it makes no sense to retry so I do want to stop all of the execution okay so how do we how do we do that um what's a good way to do that sorry this is running off the screen here uh will this work sorry the Syntax for this gets a little bit weird do I need a weight out the front something like that okay I think that works sorry let me pull that onto a new line okay so I think this should do it and then we actually do want to have an assertion here it should be the exact same exception object by the way so um exception is the expected one an
actual exception so this is a test that says I want this thing to throw an exception I want it to mess up when we get unauthorized access exception again coming back to the point I was making earlier we are going against the recommended advice cool client is not supposed to be something we own therefore we shouldn't mock it I'm showing you all of the reasons why that can be valuable doesn't mean that this is the air quotes right way to test this is something that if you're like I want confidence over this type of thing here you go like I'm trying to show you that you can build confidence however you need to okay so this one is not working it's not working because if I go back into the code I'm now catching all the exceptions right we shot oursel in the foot we
said hey we want to be careful for all of these things but there was an an exception to the exception list and that's unauthorized access exception okay so I will usually put that explicitly into here co-pilot does not know what I want this time and this time I'm going to allow it through okay so we will still catch all the other exceptions but this one we're going to not allow through okay if I go run this now there we go interesting right and actually this might be a good opportunity to say this but I don't do test driven development almost all of the time not because I have anything against it it just doesn't fit a lot of the work I try to do we're technically doing some like test driven development here because we're about to go build a retry logic around this thing
which is neat right kind of cool okay so that's cool how do we make sure that we can build retry logic now how would we even test retry logic well one way that we could do this is how do we do this with mocks it's been a little while for me I know we can so maybe let's kind of talk about this first I want to be able to retry this Loop a number of times okay so we would need something I don't know how many times right actually we've kind of set ourselves up nicely for this I just want to retry the login part okay and actually something interesting we could do is I'm kind of I'm by the way I know I'm changing the behavior of this stuff so I I should call that out as I'm doing that um what I'm about
to do is move some code around it's going to fundamentally change the behavior of some things but at the same time I'm like I think that it might be more interesting to set the code up this way so you see I just took out everything we just did so far but I did have this spot down here um so I'm going to move it down to here and we will set it up like this okay so there's a wrapper around here and now we still have this problem why is this complaining oh sure okay so if this fails I wanted to actually throw an exception I guess after three attempts co-pilot where did you get the number three from is that is that telling me something is that the magic number I'm supposed to use um okay so we'll start we'll start with that and
we can actually put that into here and actually retries is different from attempts right if you have one attempt you can have one attempt with zero retries I don't know whatever doesn't matter for now um yo so what are we working on okay yeah sorry for folks that are just joining the stream um I am going through an example that I made for YouTube already and the follow-up video that I wanted to create for that was about mocking the behavior of systems to help with exception handling and sort of trying to prove that there's some gu guidance around only mock what you can uh what you own and I want to show you that I don't necessarily believe with that guidance I think that that's um I think that that's enforcing maybe too much too many rules that we don't care about and I want
to show you that if we have full control using mocks we can do some really cool things like simulate when our systems that we don't control throw exceptions and how we can handle those so hopefully that helps uh I am watching the chat though so just uh ask questions if uh you know if you want to see or if you see an error on my screen and call it out I'm happy to be proven wrong and stuff okay so now we've changed our method in here to go do some retrying right um I want to show you something cool too but I I I want to move away from this retries thing uh being a variable here but now I need to remember how the heck I'm supposed to go count the number of calls to something um I think let's go make a new
test actually so if we go run this now do they all still pass no they don't right we've changed this I this is kind of what I was hinting at we've changed the Behavior now that we moved some stuff around um but it's good because you know this is a little bit like tdd right um it's a little bit of test driven development going on so I've broken the behavior why is that happening now so what's this test here so code path is supposed to complete right it's supposed to complete but this one is still allowing the exception to Bubble Up so you could go in fact put sorry that this is going to be kind of some duplicated code but we can go put this back here I just wanted to show you I guess that like um sorry that's not what we want
we will get let's put that back what isn't like about that oh sorry you would do something like this missing a semicolon okay so I'm changing sort of the situation a little bit so I apologize if this is getting a little bit messy um this method is still nice to have work right so if we can't get the off token can we still continue on so maybe not maybe we say hey look we can't even do the rest of it so we say hey there's no off token move on right or we say hey no off token don't go on this is a bit odd right we actually might not want this here now because if it messed up it messed up right we can't log in we don't care this was nice to have anyway so this is probably okay but I think our
tests are still going to be a little bit incorrect here by the way if this is a little bit confusing and I'm jumping around it's like I said it's because I'm trying to create the scenarios for YouTube so I want to explain them as I go but I also need to to do the work too so um now this test was saying we expect unauthorized access exception to get thrown but we I kind of like I said I changed the behavior I expect unauthorized access exception to to bubble out of this thing but technically our nice to have work like it should catch all the exceptions should okay so I'm going to comment this one out I'm going to comment it out and we're going to say what did I call the other one's code path completes sure let's reuse that um cuz we're going
to build some try logic in and that's where we're going to have to look for unauthorized access exception explicitly so this should not throw anymore at the top level we will prove again we're going to be testing some internals with retry logic when it gets built that unauthorized access exception does not retry that's going to be the thing that we're testing okay so this I think should work now all these should pass cool excellent so we get green lights on everything but we don't have retrying right to kind of prove to you that that's not happening like again going back to unit testing I like testing the internals if we said that this code should retry three times we're not asserting that anywhere and to prove it let's say we expect it to go that many times does it happen like do the tests still
pass see how they're taking longer they're taking longer but maybe that was too many times um Let me let me stop that I'm going to go 300 times on a retry instead of three so imagine that you are a software engineer at a company and someone says hey we have a bug we need to be more robust with our um our login logic or whatever call to this system this is a real type of scenario maybe not with login specifically but if you want to build resiliency into the programs and the systems and the services that you're creating you may find yourself someday working on a bug or a feature where you need to build in retry logic yes I would absolutely recommend you use the nougat package poly to do this and have a retry policy in place I just want to show you
it manually so you can see some of the details so this is a real type of scenario that can come up and now I just showed you that I changed retries from three to 300 and if I do 3,000 just again to prove a point hopefully 3,000 doesn't take too long but the point is that there's no there's no code that's testing that it's being exercised but nothing is asserting that it only happens three times clearly because it's happening 3,000 times and if we want to see that it's actually happening 3,000 times no I'm not going to make us sit here and do it 3,000 times but if I go to debug this right F5 F5 F5 it keeps doing it okay so it happened more than three times so this is funny because now this is where people might say hey look see I
told you your unit testing the wrong way like you don't have control over that thing like you know I don't know people like to make arguments about different ways to test all the time but I I'm I'm very much of the mindset like man if it's helping you have confidence like by all means you want to have confidence you want it to help with maintainability extensibility but you're trying to prove that you have confidence in the expected Behavior right now I don't because I just put retry logic in and it's going to retry 3,000 times that's not okay so how do we make sure that it happens the right number of times and this I'm I'm delaying a little bit because I can't remember in mock how to do it but I think we can say mock repository verify that something happens so verify all
is kind of nice because it checks every mock on there yeah there it is times but it doesn't take two arguments why oh sorry it's on the object itself that's why my goodness okay cool client verify log thank you co-pilot okay we're getting somewhere now so verify all is a nice catch up that says sorry I have to cough I got to mute myself I saved all of you didn't cough right into the microphone um so verify all is a nice catch all that tells us everything we set up was at least called what it does not catch is how many times so login async we are saying and I I want to be transparent too that um gener if I have to do this is kind of just from uh my experience and not necessarily because I think that this is right or wrong
I mentioned earlier that I want to very specifically set up my mock with these parameters like I really care that these were passed in I really care down here when I'm doing a verify all or sorry just a verified account it's the exact opposite because this means I I can verify that when we go to count how many times it was called that I don't care who called or what people called this thing with when I verify it I'm just counting how many times so in theory if you still accidentally had a loose mock set up for this thing we could potentially catch other situations where people called it with different parameters if that doesn't make sense I'm sorry I'm trying to move along though let me know in the chat if you want me to explain anything a little bit more thoroughly but what
I do care about is not this this is not the right answer exactly three times right this is is what I want to test this one is going to fail expected invocation on the mock exactly three times but was 3,000 times it's not okay we cannot do this right now we go oh duh that's right that's not what we wanted there you go now we run it what's it say boom so I want to pause here for a moment to talk about what we're doing why we're apparently breaking some rules for why we why and how we should use mocks but I want to show you that hopefully you're seeing the value in this right like we are testing simulating anything going wrong with this thing we're mocking the behavior it we don't like I know it's in our uh in our solution but the
whole point was pretending this is a third party thing that we don't have any control over it's calling an external system that we don't have control over now it's up to you you need to go write some tests to prove that there's retry logic and make sure that we can handle all this gracefully I'm very curious how you would do this without mocks genuinely I'm very curious because you'd have to know how to make the external system respond to exceptions and I think that the only one we have control over in a real life system is when it's an unauthorized access exception we're giving it the wrong credentials that's one of the scenarios we have too okay so this one we know that's uh that test we just did that works okay so green light yay this one it's not um it's not testing the
ret TR logic you can see it passes so this is a scenario where someone might say hey look like you're using mocks it's giving you false confidence they're right in this particular case this test is not checking enough and sorry um that might have been confusing let me put the 3,000 back okay so this test is not checking that it's retrying enough times okay so you would say yeah look like you're using mocks there's your false confidence you're like you're right that's true that's true but like there's no perfect solution for this you would need to use an integration test and you would need to make it throw an exception so how do you go do that right so my point is that it's not bulletproof it's not the Silver Bullet solves all the problems you would have to go no to write this test
now what happens here and this is an opportunity where I would probably say hey we want to go refactor some of this code is that if I want to make this other test as robust I would do the same type of thing right where I'm saying hey like that should have retried it three times okay now this test both of these should fail probably all of them fail right now but right this one says mock exactly three times and it's not same thing here wasn't called exactly three times so this one is now asserting it's it's checking the same behavior and that might feel kind of redundant so like sure what we could do and I'm not going to but you might say well Nick like this is do a lot now like we're doing some retry logic it's trying to authenticate maybe we want
to go pull this into a dedicated class maybe we want to go make like an adapter class that interfaces with this cool client because we know that we're going to be using cool client in a bunch of spots and every time we go to use it we want to have this retry logic in place yeah you might go refactor and pull this out that's one option I'm losing my train of thought here sorry um now these tests look almost the exact same but their exception type is different so I do want to come back and refactor this so these tests will go away into a single test at some point on this video but we're coming back up to here because this thing this thing's not doing what we want because it's not that like the code path does complete but we don't want any
retries so again I'm I want to keep coming back to this LinkedIn claim of you know your mocks are giving you false confidence like I do agree that if you're not paying attention to what they're doing then yeah they'll give you false confidence so if you only set up your tests with mocks this would have been a situation where you could have made a code change and it was not caught but the other point I'm trying to make is that you could have never written these tests in the first place if you didn't have mocks and we're trying to prove that we have working retry logic and that our system is resilient if exceptions are thrown so you can see that there's no one right answer here you do need a mix of different types of tests and ultimately at the end of the day
you got to use your eyes your ears and write tests that make sense okay so this says that there should be no retries but we're not actually asserting that by the way I'll say it again a lot of people say look you have an assert part here but nothing here says assert you're not asserting anything these are literally verifying things and and I will say that by definition of what they're doing they're asserting the behavior I'm expecting it says the word verify so don't be fooled it's asserting the behavior that I'm expecting and to prove it I'm going to go break this test by asserting the behavior I'm expecting we expect login a sync to be called exactly one time there are no retries okay there are no retries that's this test here that makes sense right it passes now there are no retries because
if I go back to the code we have this here if I take it out how many times is it going to retry expected invocation on the mock exactly once one attempt means no retries but it did it 3,000 times again I'm very open to suggestions but if you'd like to tell me how you can test this kind of thing without MO or if you're trying to say hey MOX unit test should never be coupled to the implementation of what you're doing then that's cool but prove to me how you can test this kind of thing I'm very open to it I'd love to learn different ways but this is how I like to do it this has saved me many many many times and maybe this is a good story time with Nick um used to write digital forensic software I'm going to go
to full camera give me one sec obviously it hides me oh I'm never coming back now it's game over there I am okay cool so I used to write digital forensic software for eight years when you are creating digital forensic software you are dealing with lots of scenarios lots of data where you don't have control over it we're talking about deleted data we're talking about recovering information from phones and computers and stuff like that when you're recovering data from deleted space it's not going to be properly formatted all the time you're going to have chunks of data that are missing because they're zeroed out or stuff that's overwritten you have to do a best effort that's the name of the game best effort it's rare that you're dealing with structured data that's perfectly intact it happens and it's great and I'll give you an example
a sqlite database so let's put our digital front hats on okay sqlite database if you had the full intact database file you could literally connect to a sqlite database off of an imaged so like someone's made a digital copy of a device you could connect to the sqlite database because you just need the file if it's fully intact that's great but there's two levels of something interesting with sqlite databases one sqlite databases can have delet deleted records inside of them still nothing to do with the file system and being deleted or anything like that no one tried to go you know delete files and cover things up sqlite databases can have deleted records in them they don't get overwritten unless it's time for the database driver to go right over them so if you were a clever digital forensic person you would say I want
to still go recover those deleted records from inside of the sqlite data datase that's one level the other level is at the file system level when truly someone tries to delete the sqlite database entirely and it's partially overwritten so you have these two levels of I might have partial files and you're going to be trying to scan over binary data trying to recover things it's not going to be perfect there are situations where you're using tools and things like that where they will throw exceptions and what happens if you throw an exception well the entire recovery process could get broken and we don't want that to happen because we're trying to help digital investigators solve crimes especially for catching pedophiles is one of the most important things that I help do and it means that you need to be resilient so that the scan or
the recovery of data can continue it's critical and this has nothing to do with distributed systems this is a desktop application and resilience and being able to move along was critical now you start thinking about distributed systems and connecting between these different systems and stuff like that it's absolutely critical that you you know some other services down you don't go oops I guess we should throw an exception in our whole service should tank too like absolutely not you need to be able to test this kind of stuff okay so let's go back to the code again my my head's probably going to disappear for a second of course it's just a Wednesday thing okay so we're back in here we were proving that we can do this right all of our tests right now should fail let me get rid of this one all of
them should fail because you know they're all expecting a number of retries this one should say retries three times as well again the naming here is not perfect I apologize just trying to move along but all of these should Now fail this one passes why does this one pass oh because I put this exception Handler back in my apologies but the other two fail because this is wrong needs to be three so we are now proving that we have retry logic in place so hopefully that helps but now we're looking at this I want to do a little bit of refactoring um these two tests are basically the same except the exceptions different so we could change this up a little bit uh it's been a little while since I've done this so I want to make some test data so the way that we
do this is we need P I think it's I don't have if it has to be public but let's do public just to make sure we need an i inumerable of an object array we'll call it um exception test data and how does this work um it can I'm pretty sure it can be a method okay so thanks co- pilot see with co-pilot I don't even have to think anymore um that's cool and then I think we call it member oh no that goes up here one sec so I'm going to copy one of these tests I'm going to comment them out just for a moment so I have them as a reference if I need them we will put like co-pilot was suggesting a theory on here client throws exception expected exception that's a fun one to say so we'll get rid of this
because we don't need that and it's going to throw the expected exception inside here okay it's going to retry three times this one says it doesn't have any data right so it's missing member data so now we decorate it with this attribute it's going to be able to go find these this one is wrong so exception test data exceptions to retry test data so only exceptions that we will have retry Logic on okay so this is called a theory in xunit it allows you to repurpose an entire test and have variable data passed into it you can use something called inline data and just declare it right here which is great but it only works for constants at least historically maybe with more advanced uh versions of The NET Framework that's not the case I just haven't checked recently so if we go run this
passes and you'll see that this is the theory I'll move this out a little bit more and you'll see that within the theory the it has two tests which means we don't have to copy and paste this whole thing every single time and in fact Let Me Go ditch these commented out ones then you might say and this is kind of a cool thing right so let's say you want to guarantee against all the exceptions that this thing can throw a URI format exception right you literally add it to your list run all your tests great you have resiliency over one more scenario right this is a nice thing that you can do if you want to build out more test cases very quickly um what else did I want to talk about um I'm doing it again time check I wanted to be able
to get to the plugin um aspon at plugin stuff I might do another live stream on that because this took a lot longer than I thought um so friendly reminder if uh if you're watching this uh while it's live if you haven't subscribed to whatever you're watching it on whether it's twitch or YouTube please or kick please do because I do want to try live streaming code a little bit more frequently it's just difficult for me to find time um okay so what I wanted to show in here and I don't know if we're going to be able to do yeah I wanted to show you with a logger Okay so let's let's do this if we're going to put a logger in here uh logging abstractions I forgot that like we get very spoiled with asp.net core this is just a console application so
now now we need a logger uh whatever I don't care about this one for now okay so forget this up top but we have a logger cool I just want to log when something happens okay this might be like you want to have Telemetry right so when I say logger this could be Telemetry it could be anything I'm not telling you that this is and I'm going to put a comment in here just because I feel awkward like people might see this but you could say like this kind of thing um I don't know if I want to say retrying because I don't know if we're going to retry handle this the way you need to for your purposes okay I'm not telling you this is how you should or need to do it awesome got web developers in the chat it's good good to
see um so I'm going to be logging an error in this case okay but now what happens so this all compiles here but what about our test oh no we don't have this passed in so this is sometimes where people will say okay like you know we can go make a mock logger well co-pilot does not know that's what I want can't predict everything unfortunately okay so we're going to have a logger okay so we'll put that here oh it's overlapping with the I don't want that get out of here okay and then I got to pass in the logger okay so this is going to be a logger that's defined strictly so now we go run these oh no they break and you can see expected invocation on the mock three times but it only happened once why did it only happen once well
there's another exception getting thrown it's not going as planned uh for folks uh in chat I do have a Discord community that you are welcome to join so if you want to do Show and Tell get help with questions and stuff like off stream and all of that there is a Discord Community you can find it on my website um maybe I should try to pull that up one sec uh it is paid for Discord Community you can join the public chat for free it's just that I don't uh I work full time I work fulltime I have side projects and I create content so this is paid for Community there is a public chat I just don't respond to it as quickly so if you want to check out more um you can go here I sent it in the chat it looks like
this goes to all the platforms so heads up but yeah there is a a free chat it's just that I don't respond to it as frequently I have to cough again one sec and yes um for folks on Twitch hey man please put that mocking presentation on the YouTube later yeah this literally I'm making this live stream because this is the content that I'm going to put on the YouTube video I wanted to be able to walk through it and make sense of it okay so let's go here I'm going to put a break point so we can see what's up right we added the logger let's get rid of that break point we can see that our log error is getting hit now it's in a catch block and again good reminder for folks if you're not familiar with catch blocks catch blocks get
triggered to catch an exception but what happens if you're in a catch block and it throws an exception the link isn't working seems to work for me that's where this should go so it seems to work but let me know okay so back in the code here catching the exception what I was saying is if you throw an exception in a catch block if I step over this this is going to throw an exception because the the logger is not mocked press F10 you can see it jumped right out it catches the exception here and continues on now this code this is one of those things you need to think about we air quotes made it resilient it catches all the exceptions it will just continue on but there's no hand here right it just returns you may want logging you may want Telemetry in
the original YouTube video I made for this I said if you have these TR catches kind of surrounding each other and you log in every single one of them you're going to have a lot of repetitive logs so you need to think about how you want to handle that but so we're in this situation now where yeah we've broken our tests but fortunately because we set things up this way our mocks are catching issues our unit tests are catching issues because we set things up with strict mocks again there's people that will say you should never be testing the implementation details I want to keep coming back to this don't test the implementation details I mean I'm trying to show you that you can absolutely do it that way and it will catch issues the tradeoff is that if your tests are only like this
if you want to go practor code a lot of the time you have to rewrite all of your tests okay so you do want to have integration tests as well these are a very specific class of tests and in my opinion if you set up your code to be testable this way then scrapping these types of tests and rewriting them and stuff is not really that much work so um I don't know I've been doing this for a little while and it seems to work very well for me I say little while like uh 12 years or so so um I don't know just find find what works for you and use it to build confidence okay so we have an issue because our logger is not set up now but we can again coming back to Mock and false confidence we should be able
to assert that that's happening so really we need to make sure that our logger is set up and it's doing log error and I really hope this isn't an extension method uh it might be it's an extension method oh we hate extension methods for mocks okay story time um extension methods and mocks don't work so well they don't work so well because you can't mock them you have to mock whatever it's calling so you'll hear me say this a lot but I don't like static methods an extension method is a static method I don't like them for this is one of the reasons I have I can't mock things easily I have to go read what it's doing inside this one's not so bad um let's just go back to the the mock setup here so we can't mock log error we want to call
this I'm just checking I don't need that I don't need that I need the message and the args so I think something like message and null but maybe not let me go back into this I can't remember what it said yeah it should be null because there's no pams passed in or does it want like a can I just do that new object an empty array I don't know if it's null or an empty array when we do args I'll find out very quickly um but this is kind of cool because some people will say this is overkill but depends I'm using a logger as an example here you like I want again I want you to think about um you're a software developer somewhere and you're trying to build Telemetry and resiliency into some of your systems and you have a feature request where
someone says you need to go put Telemetry in place and you go okay and they say I need you to prove that it works so your options are don't unit test it don't even functionally test it write no test you go roll it out and hope it works in production which means you have to go simulate scenarios where you're going to have Telemetry firing off in this case we want for exceptions okay go push it to prod and wait for the exceptions to come you could do that right and that might be what you ultimately need to do in the very end to have full confidence but what if we want to get some confidence earlier on if you want to get some confidence earlier on you can go write tests like this okay so going back here actually I think we can check in
here it's not in here sorry I got to debug it we'll run it oh it's sorry my bad it's right here fail to get all token I just wanted to find the message I forgot we didn't format it though so we take that put it right here if this still doesn't work it's because it's a a null instead of an empty array and I have a feeling it might be a null unsupported expression what is that also Don't Say It Isn't So it's more it's more extensions all the way down oh no oh that's so disgusting where is it not an extension method this is so silly I can't tell which one it's highlighting I'm trying to jump through it but I I can't you can see it's highlighting log everywhere it looks like it's on this one but this one's still an ex when
I try to go into this one it's still bringing me back to the same spot oh my God okay so if you ever hear me say that I don't like extension methods there's a little bit of indicator as to why okay so I I co-pilot was right I actually have to go mock out this entire thing this is I hate this this is awful um for in the chat I yeah unfortunately I don't know about thinkpads or anything so I apologize but um see if other folks in the chat know um okay so I'm pretty upset about this for this setup but hey this is doing it live anyway right so set up what did it say no it's not what I want okay um I really don't like this because I don't want to go mock this entire thing like I don't know what
event ID is so this isn't going to be fun um let's do this and I'll I'll wrap up the stream after we get this um this going forget this Microsoft extension logging for a moment because too many extension methods here's our own logger okay so we're going to use our own logger we will get rid of this one up here as well so this logger if I F12 into it is our logger which means I can more easily set this up again when I'm saying logger think about logger being Telemetry or whatever else you want to go publish this information somewhere so now we can go set up our logger okay and this is where I would say some people will say I don't care what's getting logged but I actually do and I do because if you've worked in systems where you're heavily dependent
on logs sometimes it's really nice to make sure that you're logging what you expect so this might be a little bit overkill for some people and that's okay like I said everyone's going to be different when it comes to this kind of stuff so I don't like prescribing things I just like showing you that you have options you could use it is any here in my case this test tells me I literally expect that this thing says this this is exactly what I want in fact it has the exact exception that we're expecting as well I wonder is there like no there's no times on here I was just curious to see if we could set it up for a number of times I you can do multiple setups but yeah I was just curious if we could do it a number of times so
that we didn't need this so um another thing if you wanted to verify how many times you're logging it you could do that as well so you could do oh co-pilot wasn't going to do it for me right you could do this I think this should pass now there we go right so we're now testing that we are calling our logging or Telemetry in error cases and this is telling us that it's doing it exactly three times even for the error what about this one up here how many times should this log it's a bit of a trick question right let's go back to this code I know there's not tons of people on the live stream but if you want to participate here's your opportunity if we have an unauthorized access exception how many log messages should we get right we're looking at this
code here if we have unauthorized access exception how many times do we want to log that or how many times are we logging it is a better question people seem shy that's okay the correct answer is zero we don't want to log the way this is set up we don't want to log when there's an unauthorized access exception we just want to keep it going so we can prove that we can literally write a test that says we don't expect that to happen now implicitly that is what's happening here this test sorry this test uh Explorer is kind of a mess right now but right if we go run this it passes already there is no setup on the logger on this test but we could we could say that we explicitly don't expect it to be called with anything sorry this uh co-pilot do
your thing so we don't expect this so we're going to say I don't expect logger to be called at all right so that means any exception being passed in any string you pass in and I'm going to say at the end never I never expect the logger to be called and it passes that means means if someone broke this okay someone breaks this behavior and they say I'm going to give you an exaggerated example because you probably don't want something like this in your code right probably don't want this so our tests are telling us hey look we expected that there should never have been a call to this but someone did call it now again someone who doesn't know they might say let me just go update the test like yeah it's you know there's like I said there's no Silver Bullet for this
stuff you still have to you still have to think through it this is what pull requests and code reviews and stuff or four you know you can fix this by going to update the test but the point is that you had something in place and you'll hear people say this all the time like oh like you know don't test the implementation details I am literally testing the implementation details here because I care to prove what they're doing because is I'm trying to build confidence in a particular way so the test should pass when it's behaving properly and they do so I think that might be an interesting stopping point um but what we got to see here I'm got to go back to full camera I'm going to disappear for a moment I apologize don't know why it's doing this but here I am um
and we'll put the chat up too I think yeah you can tell me your profession like go you can feel talk say whatever you want in the chat it's fine um what we were looking at here though is kind of like I'm calling it like breaking the rules because people are saying don't test this particular way I would still in this particular case if I'm able to would want to be able to set up integration and functional tests but when we do that kind of thing almost exclusively you're testing happy paths you can test error scenarios but you don't have a lot of control over making these external systems have errors and you either you or other people on your team if you want to be able to have test coverage on this kind of stuff you might say well it's impossible we have to
test it in produ production we have to put the code into the situations in production where the errors are occurring and then we can see that it's working and I just think that that's not true it's not true because I just proved it to you that we can go test that kind of stuff when you're mocking things out you have full control over how your code's executing that's not to say that that's the only way and the best way to test but if you want to have test coverage over these types of scenarios I think that that's very valuable that's awesome professional editor web developer and artist SEO yeah that's great that's a lot of lot of good stuff there so I think that you know when you're Building Systems I would absolutely say that you should have system type test in place right the
reason that this code that we were looking at is very challenging to test with an integration test is that the code itself will call out to a website if you use cool client you must have internet access and it must be able to access that site and if you think about that in your use cases you might be saying hey we have something that connects to a service you might be able to go you know spin up if you're familiar with test containers you might be able to go spin up containers that run those services sorry I'm not looking for any services but I do appreciate the offer um you might be able to spin up test containers to be able to go connect to these other services that you need to interface with right so you could in fact write integration tests that do
exercise some of these things but again I come back to how would you like to do that for error scenarios how do you want to prove that you're retry and resiliency logic is working hello again from you're you were on YouTube earlier weren't you awesome well thanks Bob James I appreciate it on the the multiplatform streaming um that's great so yeah to to kind of summarize um what's going on here there's different ways that you can test stuff right and you can approach things in different ways it's all about getting confidence in the code that you're trying to exercise and for me when it comes to error scenarios and things like that I would love to hear other people's opinions and their approaches for being able to test error scenarios without using mocks if you're trying to make your third party Services throw errors I
don't know how you're doing it yeah I usually like and this is a good good comment and thank you for putting in the chat right I usually like testing some implementation details but testing logs feels wrong and I I do want to admit that like a lot of people will see that and go like man like that's just Overkill it's just Overkill and like it probably is for many people but here's what I have to say right and I'm not I'm not um I'm not disagreeing with you on this so I really do appreciate the comment you'll often find that like my the stance that I like to have on things in general is like I like to acknowledge that we we all approach things in different ways I think that's incredibly important because having extreme opinions like this is absolutely right or absolutely wrong
is like it doesn't that doesn't feel right to me so you know testing logs feels wrong like I agree that a lot of the time for many people that's the case and what I have to say about that usually is like well why do you have the logs because it sound like hear me out it sounds like you don't care about the logs right like if you don't want to test it because it feels like it's wrong it feels like it's Overkill sounds like the logs aren't important and that might be the case so then why do you have them right and I I'm not trying to call you out or anything like that right it's like um and sorry for for in the chat there I I don't have time to review people's uh like if it's SEO and you're looking for services and
stuff like that I don't have time for that I apologize in advance if you are Building Services you're writing code and you want to uh discuss that um that is definitely for the the paid Community you're welcome to ask open-ended questions and stuff in the public chat there and they will take time for me to respond but if you want me to review things uh I being totally transparent I don't mean to be rude I quite simply don't have time for that um when it comes to logging the the scenario that I'm trying to kind of call back out here is like yeah in a lot of situations I really do care about logging in Telemetry in situations where I don't I fully agree that like then I may not test it so even though I'm showing you like hey look I really care about
logs and Telemetry there's certainly situations where I don't and I'll go throw an IT do is any right or I might use a loose mock for a logger and I often find myself going to I really need to log here then like if I'm never going to use this so I like to go with the idea of is this exception being thrown if it is up to the application handle those and the and the unity service would be working fine yeah so if you're using unity in this case for sure so you know it's it is absolutely situational and that's cool right so again trying to present to you that you have different tools and different paths that you can go use so if if you have exception handling in your application set up a particular way so say it's being handled more at a
higher level and you just want to make sure that that higher level can catch stuff great um maybe you don't care about logging at all of the more granular levels so say you have more granular TR catches they might do some some logging you're like I don't give a crap if that's actually getting logged it's just kind of nice when I'm debugging if it's there but maybe you really care that at the top level for you know for big bad unhandled exceptions that you have a global exception like that's getting logged by all means right like you can approach things in very different ways here so um yeah thank you for kind of sharing that perspective because I think it's important just to call out that people will approach things in different ways but it's all about making sure you have the tools to do
we need to do so I hope that was helpful um I'm going to sign off here in just a moment but I kind of got to do the obligatory uh Dome train thing that I got so I got chuses on dome train so if you find this kind of stuff helpful and I hope that you do I do have courses that you can check out so I'm switching over here so I have these courses available on dome train I do have at least two more coming hopefully by the end of the year I will not reveal yet what they are because I don't have um like a I have verbal agreement from Nick chaps but we haven't signed off on them but if you are interested in refactoring I do have this refactoring course and if you are basically very new to programming there's a
getting started C course and there's a deep dive that builds on top of that so these two courses together getting started in the Deep dive there is also a bundle that you can check out from Zero to Hero so I'll click that right you can get both of these courses they're discounted 20% and like you can see here 11 and a half hours of content so you can check that out and yeah that's the live stream thank you so much for watching um I will be guaranteed to be live Monday night 9:30 p.m. PST and I'm hoping that I can do another live stream um because the other for coding sorry because the other content I want to put together is about doing plugins for asp.net core so thank you thank you chat for being here I appreciate it I appreciate the input and the
thoughts enjoy the rest of your day or if it's evening where you are have a good night and we will see you next time take care
Frequently Asked Questions
What is the main focus of the video?
In this video, I'm focusing on demonstrating how to write unit tests, particularly when dealing with external services and error scenarios. I want to show you how to effectively use mocks to handle exceptions and ensure that your code is resilient.
Why do you prefer using mocks in your unit tests?
I prefer using mocks because they give me complete control over the execution flow of my tests. This allows me to simulate various scenarios, including error handling, without relying on the actual external services, which I don't control.
How do you handle logging in your tests?
In my tests, I often verify that logging occurs as expected, especially in error scenarios. I believe that if logging is important for understanding the application's behavior, it should be tested to ensure that the correct information is logged when exceptions occur.
These FAQs were generated by AI from the video transcript.