BrandGhost

How to Write Blazor Unit Tests With bUnit and xUnit

You've been building Blazor applications and the voice in the back of your head is reminding you that you need to write tests. But how? What tools do we have access to in order to unit test Blazor components? Let's dive into bUnit and xUnit! Have you subscribed to my weekly newsletter yet? A 5-minute read every weekend, right to your inbox, so you can start your weekend learning off strong: https://subscribe.devleader.ca Check out more Dev Leader content (including full in-depth articles with...
View Transcript
if you're using Blazer and you're having some challenges getting started with unit tests don't worry you're not alone I found that this is a really common challenge for folks that are dealing with UI Frameworks that have some type of markup for the front end visualization and then some code behind that goes along with it and the classic example I've seen with this is working with WPF so again Microsoft tech using C and using zaml and then having some type of mvvm setup you have your code behind your view models things like that people seem to really struggle with writing unit tests for that and Blazer is no different because we end up having some type of frontend markup language and then you have this code section which is some logic that goes along with it and of course if our code is all pulled out into these other classes it seems to be a lot more straightforward to go right test for them but when we're dealing with blazer components and you have code in the section at the bottom of your file along with the markup at the top people seem to have some challenges with getting their test set up so in this this video we're going to be looking at using B unit along with xunit to write tests for our Blazer components and two things before I jump over to visual studio first I apologize for my voice I am sick I still wanted to put some content out and the second thing that I wanted to mention is that if you have not subscribe to My Weekly Newsletter yet please do so I'll have a link to that in one of the comments below and you can check that out it goes out every weekend and has software engineering topics along with c and net examples and going forward I'm going to be writing dedicated articles once a week that will only show up in that newsletter so the only way that you're going to be able to see that is if you're subscribed the newsletter itself is totally free so it costs you nothing to subscribe and I'm hopeful that you'll find that content useful in your software engineering Journey okay enough blabbing for me let's go check out visual studio and see how we can test our Blazer components all right the first thing that I'm going to point out in our solution is that we're going to have our base project that has our Blazer components and this is just an example application that if you start up a new project in visual studio for Blazer it'll put this together for you and I've just added a couple of other things here but it will have the counter example in the fetch data all of this stuff just comes as part of that project template the second part that I want to point out is that we'll be adding a new project here which is going to hold all of our tests while it's not a rule that you have to have a dedicated project for your tests this is something I would highly recommend so that you're not shipping code that is test code and you can keep those things separate so to get set up with being able to write test for Blazer we're going to be looking at B unit along with xunit so in my other videos I always talk about using xunit it's one of my favorite testing Frameworks and have xunit work in Visual Studio there's really three packages that we're going to be looking at the first is xunit itself and then we have the xunit runner for visual studio as well so that's this other package that I have here and then the third package we require is this microsoft. net. test. SDK and these three things together allow us to write unit test for xunit that show up in the test runner in visual studio so if I open up this test Explorer here you can see that we have all of these tests and these packages allow us to have that B unit is going to be the new addition for testing our Blazer components and we're going to be using B unit because it allows us to actually render the components and check out the visual state of those components in code and this is a really good opportunity to pause for a moment because I think a lot of the time people struggle with writing unit test with some type of visual framework like a gooey framework so whether it's WPF Blazer anything else because they're thinking about how do I click through how do I navigate things like how do I get the UI set up in a way that I can go test it if you have a really complicated user interface or even something that is simple but you have to go through a bunch of steps it can be challenging to think about how you're going to get that set up I think this is a good opportunity to pause for a moment because I think the two biggest challenges we face when we're writing unit tests for some type of UI framework is that we have one a mix of code and markup so we're talking about the visual aspect of what we're dealing with in some type of markup language plus some code that we want to be executing that's one kind of challenging part and then the second part is really about how our user interface works and how we can get to that state in the user interface to be able to test it properly so a lot of the time I think people kind of think about something like selenium or some other type of clickable automated user interface navigation where you have to be able to click through things and get to that state just to be able to execute like a test case and while those types of tools can be useful I think there is so much more we can do and B unit is going to show us how we can do that without actually having to go set up all of this stuff to go click through things and you know have these windows popping up and navig skating through stuff in a browser it's totally overkill for this type of thing but I just wanted to call that out because I think that's a bit of a challenge for people getting started with this kind of thing all right so once you have these packages installed we can actually go look at starting to write some tests for our code we're going to be looking at two different types of tests in this case and the first is going to be for the counter razor page that we have here and the second is just for a component that I've added which is extremely lightweight it's just a component that has a header three on it and no actual code on it but it's just to illustrate how you can get set up with working with your own component if we look at our component test this is actually the most straightforward test that we have to work with I'm going to call out a couple of things about how this file is set up to be able to run tests and then we'll go through the test itself the first thing I'll note is that with xunit we need to label our test methods with a fact attribute you can use a theory but in this case because we're not passing in parameters we're just going to be using a fact this fact attribute allows us to see the tests in in the test Explorer here so it is the thing that indicates to xunit that this is a test method the next thing that I'll point out is that this test class inherits from test context and test context is something from B unit that allows us to work with getting rendered components from Blazer now you do not have to actually inherit from the test context as part of your class but in this particular case we're going to be using this pattern to illustrate how this works when we look at our actual test method here the name and Convention that I follow is generally three parts that have to do with the state the thing we're testing and then something about the expected result and to be more accurate for how I usually do this it would probably look something like this and that's because I am testing the header and the current state is just the default state so I haven't set anything up that's special it's just what we get when we construct it and then we're going to be looking at the title so this test in particular is very simple and what we're going to be doing is calling render component with our component that we're testing render component is actually a method that comes from this test context so because we're inheriting from that with our test class we do have access to this method and this is really where all of the Power of B unit comes into play Because when we do this we get an instance of a rendered component that we can go look up information on so again this line here line 14 is calling this render component method from B unit it is using the type of component that we want to be testing and because we're not doing anything fancy here there's no setup or anything else it's just the default state of this component and as I showed you earlier in the video this component is quite trivial so there isn't actually anything to set up on it anyway but what can we do with this rendered component and what types of things can we start to check out well with a rendered component we have methods like find where we can actually go look for different markup so in this case I'm looking for an H3 tag and then we can go verify that that markup once we found it matches some explicit text that we provide here in this case our component just has an H3 tag that's called component and there's nothing else that's really part of this component at all so these lines from 16 to 18 give us this syntax that's find and then markup matches which sort of equates to something like an assert inside of xunit and just to give you a counter example of how this works and how we can still fit it into this test what I tried to do was look for an H1 tag and because there aren't any I wanted to ensure that when we try to find all of the H1 tags that we get an empty collection bag and the reason I'm using find all here instead of find is because find itself will actually throw an exception because it can't find any H1 tags so this very simple test is really doing two assertions the first is just that we have a single H3 tag that has component as the name and that there are no H1 tags on this component and if we check out the component itself again very simple and straightforward you can see there are no H1 tags and there is a single H3 that's called component so that's it for this test just a quickly recap we are inheriting from this test context which is part of B unit and then that allows us to call render component from B unit on this test context and pass in the type of the component that we're interested in rendering once we have that rendered component we can go look up different markup and assert that that markup matches what we expect so this one was pretty simple and that's because the component itself is quite trivial so let's go look at the other example which is slightly more complicated so if we go to look at the counter page that's part of the template project when you're making a new blazer application we have a page title that's counter we have an H1 tag that's also counter but then we have a label that tells us the current count that we're at and a button that allows us to increment that count there will be some code behind on this page and your eyes are probably drawn to this fix me which I'll touch on in just a moment but this is just the standard page that we get as part of this template application when we're looking at this page some things that we can consider testing are that we have the right H1 title that the text that we have here is correct or maybe we want to be able to test that we can actually press this button that says click me and have that count increment however the tests we're going to be looking at for this example are going to be checking the H1 title as well as whether or not this label shows the current count properly all right so in the test file for the counter page this looks very similar to the last test file that we looked at we are going to be inheriting from the test context just like in the last example but one of the main differences is that of course we're not dealing with that other really basic component we're dealing with that counter razor page so the first test that we're going to be looking at actually ensures that we have that H1 that says counter on it so it's very similar to the other component test that we looked at that had an H3 but instead we're trying to ensure that we have this H1 here this test is of course super basic but let's go jump over to something slightly more complicated where we want to go check the count that we have as part of that label again this test is going to render that component with the default state in this current test and then it's going to look for the P tag and then ensure that we have this current count as zero because that is the default state that we expect but what about the state that's not default what happens when that current count is actually something that's not zero say someone's pressed that button several times what should this label say now there's a bunch of different ways that you can go do this and one way that you could go look at this is actually simulating that someone's pressing that button several times so if you wanted to say I want the current count to be five and you want to check that label's text after that count is at five you need to simulate pressing that button five times and then rendering that component to get the text another way that we could do that and this is my preferred way to do it when we're just looking at more of a unit test approach is actually to set that count to five so that we can go look at what's there on that label without having to go do some other functional operations like pressing a button in my opinion both of these types of tests have a tremendous amount of value when we're looking at the unit testing approach like a much more isolated like just set the value and let me get the the Tex off of the page that's really isolated it's just showing you that the label is working as expected almost like imagining what binding would look like if you were thinking about a zaml application and the more functional approach of pressing that button is much closer to what you might have in some type of automated UI test if you imagine a clicker application simulating actually pressing the button on a browser because it is more like a functional test it's simulating the real behavior that a user would have if they were pressing that button both of these situations offer value I think that if you had time to go write tests you'd probably want to be able to include both types and that's because the unit test approach will give you more granularity for when something breaks and the functional test will give you some confidence that as a user is interacting with your application that behavior is as expected let's jump back over to visual studio and see what we can do about setting this value for more like a unit test and how we can go assert the content and that P tag all right so B unit has this ability for us to be able to set parameters and render on this render component this method signature basically does this in place so we don't get a new rendered component back we're actually mutating the rendered component that we're given but you'll notice with this syntax here that this current count is actually underlined with a red squiggly and it's not compiling because we can't actually see this current count because it's a private field now now personally I'm not a big fan of how this approach works so I am going to follow up with another video about refactoring this to make it a little bit more streamlined for a pattern that I prefer but this fundamentally comes down to the fact that current count needs to be exposed so that our test can see it properly and that means that we have to go modify our Blazer page to be able to expose this current count and do something so that this test can see it and that we can modify it if I jump over to that page this is where this fix me comes in that you probably we saw earlier and I've left it in as a comment so that we can toggle it and see the difference so as a field which is what we have as standard here we have this current count field it's an integer it's not readon or anything like that and that's because the button that we click needs to be able to modify this current count but personally it makes a lot of sense to me that it is a field and that's because nothing outside of this razor page needs to be able to see that current count but once we start talking about how we might test this we're in this position where we don't have a lot of control over the razor page that we're testing we could use B unit to actually go click this button and that's entirely an option like I called out earlier and we could go simulate functionally that we're clicking this button several times and that would give you the behavior that a user would have if they were interacting with your application however if you strictly wanted to prove that your label syntax that you have up here is actually working as expected regardless of whether or not this button is being pressed and just the state being reflected in the label is as you might expect we don't have control currently over how you would set this count so like I said this is not my preferred way to do it but we could go ahead and make this a property that's exposed and it has a getter and a Setter on it and we have to mark it with this parameter attribute as well these two changes together along with the fact that it's now public and not private allow B unit to go see it so if we jump back over to those tests we can now see in here that there's no more red squiggly because B unit is able to see this current count off of this Blazer page if I would have left it as just a public field instead and not added the attribute on it then we would see that when we go to run this it would complain to us that it's not a public property and it's not marked with the right parameter attribute so those changes coupled with this line 34 and 35 code allow us to actually set the current count I've just set it to five but you could put anything you want here in your test and this rerenders it so that when we go to ask the component for that P tag we can now check that the markup actually has the current count as 5 instead of zero so to quickly recap on the test in this file we had something very similar to the example before where we're just looking at the H1 tag the other example had an H3 that we were looking at you could go ahead and assert that there's other text or other basic fields on this counter page if you were interested in that and then these next two tests that We examined started to look at having different state that we wanted to go pull from that page the first example was just looking at the default state so we didn't really have any setup or anything fancy to do and we could just go ahead and pull that P tag and ensure that it is what we expect the second example that we looked at here actually required us to go make some modifications so that we could go set that current count property and we actually had to make it a property instead of a private field so that we could make it testable but once we did that we could actually set that value using some B unit methods and then assert that that current count is five for that P tag as I mentioned it's not my preferred way to do this but I wanted to illustrate that if you wanted to make some simple changes you could go ahead and make modifications to support this however I would prefer something like like a view model in this case and I'm going to demonstrate that in my next video which I'll link at the end of this one when it's ready all right so there you have it that's the basics of getting Blazer pages and Blazer components tested with B unit and xunit xunit in this case is just used for us to be able to have that test harness hookup so that we can have the test run inside a visual studio in that test Runner and then B unit gives us the flexibility and the power to actually render those components and get the state right off them the added benefit of using B unit is that when we're pulling that state it acts like an assert so if you were looking for a tag for example and that tag wasn't even there it will throw an exception and act very much like an assert in the examples that we looked at we covered just the really basic ideas behind how you can render a component pull that state off look for some different markup and see that it's as expected but there's more complex things we can do and that's because I limited this video to just looking at it from like a unit testing approach approach where we're just looking at some really small units of operation and checking some really basic functionality of the components or the pages that we're interested in from here what you're able to do is start looking at things like clicking buttons or navigating and interacting with your pages or components in different ways to look at the state that comes after that or like I mentioned in the video that I'll link right after this one when it's ready we can refactor the cod in a different way that I think is more elegant and not exposing things as properties and necessarily so that we can go test things still in a unit testing approach and personally I like this pattern a lot better because I have a lot more experience with it coming from a WPF background for many years before this and it feels like it's very applicable in this Blazer case as well so when that's ready it'll be linked right up here and thanks so much for watching we'll see you next time

Frequently Asked Questions

What are the main challenges of writing unit tests for Blazor components?

I found that the two biggest challenges people face when writing unit tests for UI frameworks like Blazor are the mix of code and markup, and figuring out how to get the user interface into the right state for testing. This can be particularly tricky because you often have to navigate through various UI elements to set things up for your tests.

Why should I use BUnit and xUnit for testing Blazor components?

I recommend using BUnit along with xUnit because BUnit allows us to render Blazor components and check their visual state directly in code. This makes it much easier to write tests without having to set up complex UI interactions, while xUnit provides a solid testing framework that integrates well with Visual Studio.

How can I test the state of a Blazor component without simulating user interactions?

You can test the state of a Blazor component by exposing the properties you want to test as public properties with getters and setters. This way, you can set the state directly in your tests without needing to simulate user interactions like button clicks. This approach allows for more isolated unit tests that focus on the component's functionality.

These FAQs were generated by AI from the video transcript.
An error has occurred. This application may no longer respond until reloaded. Reload