Flutter: BLoC Testing in 10 Minutes

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
blocks are a fantastic tool to manage state in your flutter applications and today I'm going to show you how to test a block let's get to it okay so I have a block here this is called a pet block and it extends block pet event pet state so we're taking in pet events we're emitting pet State there's also a pet repo that gets provided here in the Constructor our initial state is pet initial and then whenever we have certain events we uh call these functions so on a load pet event we call the load pet function which is right down here uh the same for the rest of these really nothing crazy so I'm going to show you two really important things so the first one is there's this package called block test by the people who make block uh that makes this really nice and easy um the second one is a package called mocktail so I'm going to add both of these I do already have so if I pull up my Pub speec I do already have block test uh right there you can see that uh probably should be a Dev dependency I'm not sure why it's not makito as well man old project okay so we're going to go ahead and import mocktail and then we'll head back to our Pet Block and I'll right click here and if I create or if I click go to tests it will prompt me to create the test since I don't have any so I'll go ahead and hit that green button there to create one and it gives us a main method with a test widgets function so what we want to do instead of using the test widget function is we want to use the new uh block test um there's a nice little shortcut right there and it looks something like this so we have a pet block that we're working with and we have a pet load uh sorry is it load pet load pet it is load pet pet ID of we'll say one and then we have the states that we want to model here uh so we want a pet loaded and we have a pet that we'll need to check against okay so there are a couple different things so let's go ahead and import block test you can see that we're importing our Pet Block uh we're importing our pets block which we shouldn't need okay um and there's an argument missing here and then we need to Define this type so we have a block test this is the name of the test so I'm going to go ahead and group this first so we'll group it and say Pet Block and then I'll come over here I'll paste let this format itself and we'll give this test a name so uh handles load pet successfully this is the name of our test now that we're here we need to uh create our uh repo for our Pet Block right so if we look at this again we can see that it takes in a pet repo this pet repo is actually kind of big and I don't really want to use the whole uh an implementation of a repo on our tests so instead what I want to do is mock that uh so I'm going to say class mock pet repo um extends mocktail is it mock yeah extends mock implements pet repo now what we can do is we can create an instance of this so I have right here uh final uh mock pet repo equals mock pet repo okay now we can pass that here Mo pet repo that satisfies that contract since it's implementing pet repo and then we have a pet right so final pet equals pet uh yep that's the one um and then there are a couple fields that we need oh actually we don't need any Fields but we're going to go ahead and give it one uh I'm going to say luna since this Project's named after my dog Luna um okay so we have our pet we can expect our pet to be loaded this can't be const anymore because that value is not a const um I guess we could make it one but that's not really the point so if we run this it's going to fail I'm going to go ahead and let it run and we'll see how it fails perfect null is not a subtype of stream pet mock pet repo get by ID so mock pet repo is failing so what we can do here is if we look at the mocktail uh documentation here you can see how stub and verify Behavior so in our case all we really need to do is use something like this win so we can just paste this and we want to say when mock pet repo doget by ID and then we know the ID is one right because we are specifying it down here then return uh and we can take a look what does this return so mock pet repo returns a stream stream um from iterable elements we have one element and that's our pet now if we run this again okay invalid arguments then return should not be used to return to stream use then answer oh that's fair uh when you're doing asynchronous returns um one of the requirements for mocktail is that you use then answer instead of then return oh my goodness this hard to type so let's run this one more time we should fail again but for a different reason yeah perfect so you can see here expected pet loaded but we got pet loading and then pet loaded so our block is emitting two states why is that well it's actually really straightforward if we look at this we emit pet loading and then we emit pet loaded so we have a couple options we can go back to our test and we can either either add pet loading right here and run this and it should pass it does or we have the option of skip one so what we're saying with Skip One is skip the first thing that gets emitted when you expect an output so in our case we would skip the pet loading and now we're just checking against pet loaded one more thing that you could do if you're interested in it like maybe we want to validate that we are calling mock pet repo um this test kind of does that for us because the way that we're stubbing it requires that it actually gets successfully called to return the stream that we later validate down here so it's it's a fine test as is but I do think that if you wanted to go a little bit farther you could right so we could say something like this with our stream we can set a new variable called called and then say called is equal to true if we look at our block test here we can see a couple different things so there's expects there's verifies there's errors there's tear Downs there's a ton of documentation here which is really fantastic um verifies is an optional call back which is invoked after expect that can be used for additional verifications or assertions verify is called with the block returned by build okay so what we can do is something like verify and we can see that verify takes in well shoot I had one on hand is called with the block return from build so if we go here please so this would be the block and we can expect that called is true let's run this again okay that passed and then just to make sure that this works I'm going to set that to false yep expected false actual true so if you needed to do an extra assertion or to validate that this was being called you have this option um fun fact you can also do this with mocktail so you don't have to set up a variable here and then change the variable here you can actually reference this and then call like do called on it to see if it was called or call count or something mocktails a really fantastic library for mocking and I highly recommend checking out more of it I like this pattern because this pattern Works across every language and I work in a lot lot of different languages so this is consistent for me so if you wanted to go farther you would take this and you would basically stub out a new test for each um event that your block responds to so if we look at this we would we did load pet we would want to handle delete Pet update pet archive pet unarchive pet and AD pet but additionally there's a couple other things we should do too and this highlights some issues right so for one this can fail right this this totally can fail this is an a call that we have no idea what's happening outside from our blocks perspective we have no idea what's happening with this call and I'll tell you it makes a network call uh behind the scenes and if it makes a network call it definitely can fail so maybe we should handle the fact that this could fail um so how do you handle that well it would actually be really similar we would come back to our block and we could basically copy this and paste it uh the difference here is that we would need to change our um pet repo stubbing right so we can't just put that here because if we tried they're at the same scope right um and what we want to do since this defines a test and then runs it afterwards uh what we want to do is instead we can leverage a setup function so there's a setup like this and um we can take our second uh block test right here add a setup function like this and this time we want this to uh I don't know throw error right something like that okay this should meet that needs so this is handles load pet when error let's run this and it should fail it failed look at that instance of error okay yeah that makes sense okay so we're throwing an error here right uh I don't really care about this called anymore so I'm going to remove this verify here just to keep things simple and yeah that's fine we can remove it here too it's not really relevant for this test anymore okay keeping this simple so it's a little easier to reason with uh so we have this error that is happening here when we load a pet we are throwing an error so how do we handle this um the main issue is that our block isn't set up to handle this right so we try to do this but if we catch an error we probably need to do something else right so we could do pet failed if we look at our test here we have pet failed instead of pet loaded and keep in mind we're skipping that pet loading um emission still great that passes I'm going to run them both one more time they both should pass so I'm just going to talk over it while it happens but this is how you can set up block tests literally using block test uh to handle scenarios where my block receives something and it needs to output something uh this is how you can write those tests really nice and easily so remember don't just handle the happy path handle every path and then a good way to know how many tests you should start with for each one of these you should have a test I'm not going to write them all on camera because it's going be a waste of your time at this point not much will change uh but you can see like 1 2 3 4 5 six you should have at least six pets and if these can fail you should have a permutation for each one that can fail so for load pet you should have two because you have a success path and a failure path uh and here's a spoiler delete Pet should have two update pet should have two archive unarchive ad those should all have two ad might actually even have three because of the extra failure path in that one anyways that's it that's how you test your blocks in flutter with block test and maito um if you don't want to use moito I'm sorry mocktail uh not moito that's how you use mocktail if you don't want to use mocktail you can use moito or if you um just want to you can also uh implement the mock yourself um I originally was going to do that this pet repo is quite big uh so it would have been a bit of a pain to implement that and mocktail makes that nice and easy um if you found this video helpful don't forget you can subscribe to the channel to get more flutter videos with tips tricks and other fun things uh and then on top of that if you really found it helpful send it to a friend who might find it helpful you'd be their hero my hero and you'd make everyone's day a little bit better thanks
Info
Channel: Brad Cypert
Views: 915
Rating: undefined out of 5
Keywords: bloc design, bloc pattern, flutter apps, flutter bloc, state management, unit testing
Id: xVArgPOXT-U
Channel Id: undefined
Length: 13min 49sec (829 seconds)
Published: Sun Mar 17 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.