 In today's Visual Studio Toolbox, Chris Woodruff and I continue talking about Web API. We're going to look at something that's brand new in ASP.NET Core and that is integration testing. Hi, welcome to Visual Studio Toolbox. I'm your host, Robert Green, and joining me today is Chris Woodruff. Hey, Chris. Hey, Robert. This is part two of our three part for now, series on building Web APIs. Yeah. So in part one, we built a Web API, turned out to be pretty straightforward. Awesome, Lee. And then today we're going to talk about integration testing. Yeah. So we're going to be using ASP.NET Core Web API. And we're going to use a different kind of testing. So lots of people know about unit testing, testing internal components and internal parts of your solution or projects. Yep. And I did a four part series turned out with FilgerPixie on that which may or may not have been published by the time this episode got published. I did done a bunch of recording last week because VS Live was in town. So I got Phil and some others in here. Awesome. And then we're doing a bunch here. And then I'll figure out when to publish. Oh, that's awesome. If the Phil one has started, then go watch that. If not, then watch it when it's out. Either way, I'll put links in this episode to that one where people can go find it. Yeah, Phil's a great guy. So that's unit testing. And that would be testing the code that you wrote inside the web API, which of course you need to do. But we're doing a different type of testing here. Yeah. So we're actually going to be testing the actual APIs that we built. OK. So in the previous episode, I built an API that had two entity types that we were building APIs against albums and artists. We were using the Chinook demo database that Microsoft created some years ago that I use for all my demos. Well, that and my baseball database. But the baseball database is a little complex. That thing is gigantic. It is. It's fun, though. But we're going to use Chinook. We're just going to take what we had, the project that we had from part one. And we're going to use it for this to build integration tests. And we're actually, like I said, we're going to actually hit our APIs. And we're going to call a use a HTTP call with a verb. And then we're going to get a response back. And we're going to make sure that that response and the response code is what we expect. And if it comes back as expected, the integration test passes. And if it doesn't, it fails. So this is integration testing. So the unit testing would be inside the web API. And now we're saying that if from a client you call the web API, do you get the right stuff back? That's an integration test. So I think you should test external. I agree with that statement. You should test. You should test. You should test over and over again. Yep. But we're going to be leveraging and using the exact same coding styles that you would use for internal unit tests. So we're going to use XUNIT for this. So you'll probably look at this and go, it looks just like my unit tests that I build every day. And it's like, yep, it does. It just tests different things. And we'll explain. Sweet. OK. So you can see I've got my application. I've got Visual Studio running. And it has a project in here called Chinook Core API. This is the one we built in the last episode. Yep. Same exact code. And so what we want to do is create an additional project on this solution. So we're going to say, add new project. And then we're going to come in. And under .NET Core, we're going to say XUNIT test project. Now you can use MS test. I like XUNIT myself. And in here, we're going to give it a name. And I'd like to give my tests the same name that I give the projects that they're testing. So I'm going to say Chinook Core API dot. And for this, I'm going to do integration testing or integration tests. Because I will set up two projects against a API, against a web API project. I will set up a integration project, integration testing project, and I'll set up a traditional unit testing project. Because I want to test both sides. Good. So for this, I just call it. And you can name it whatever you want. I just call it the name of the project that I'm testing dot integration tests. And we're going to say there, it will stand up that new project. And pull in all the dependencies. The first thing you want to do is, say, add reference. And then we want to allow. So it pulled down XUNIT for you. Yeah. And I'll show the new get packages in a sec. Because we have to install some additional new get packages. But we want this integration testing to have a reference back to what it's testing. So we just need to give it that reference so that it knows what projects it has reference to. So we say that this integration test is going to have a reference back to the Chinook core API. And if I open up the dependencies and new get, you can see that we have a number of different new get packages already installed from this project template. So we have Microsoft.net.test.SDK. We've got XUNIT. And then we've got XUNIT.runner.visualstudio. We need some additional new get packages to allow us to do integration testing. Now I have that code all up and running. And I'm going to install them. And then I'll walk through what those are in here. Now let's go to package manager console. And this is a gotcha. I get burned on this every time I do this. This default project always defaults to the original project. So it will default to the web API. So you want to make sure that you're pointing that to your integration test. Because we want to install those new get packages with the integration test project. So I'm going to install everything. And then we'll take a look at the packages that we installed. So the first one is, and you can see it just came in. And it's being stood up, is microsoft.asp.net. Or asp.netcore.mvc.mvc, which when you do unit testing, you don't need all of that to be brought in. But I'll explain why you need that for this type of testing. And then we also need microsoft.asp.netcore.diagnostics. And then the most important one that we need is the microsoft.asp.netcore.testhost. And that will allow your integration test to stand up a hidden instance of your web API project so that the test can actually hit it. But it actually doesn't bring it up in the browser. It kind of hides it. Oh, that's kind of cool. So rather than publish the API and then call it from your integration test, you're basically creating a local version that gets stood up that you can call locally. Yeah, and it's just a small, it's a small little host that just hosts your API. And it lives as long as your tests live. And when the tests are done, it shuts it down and disposes of it. OK, so we have all of those dependencies. So we can hide that. Just like I did in my previous project, in the previous video, I'm going to get rid of this unit test one. Because one, it doesn't really have anything in there anyway, and I like to start out with a clean slate. So I'm going to come in and I'm going to add a new class. So for the time being, I haven't really found that anyone has created a X unit ASP.NET core unit test template. At least I haven't found it in here. So I'm going to create it myself. So I'm going to call it albums integration tests.cs. You can name it whatever you want. There's no convention for the naming of these. So I'm going to say add. And I'm going to go out and get my trusted code. And I'm going to bring in a few things. So the first thing that I'm going to have is, and let me fix these so we can see everything, just make sure that we bring in those using clauses. So what we have here is we have two private read-only properties. And one is of type HTTP client, and one is of type test server. So our tests have to have both. We have to have a client. We have to have a server. The client makes the HTTP call, and then the server does the work and sends back the response. And again, this is cool because you don't have to take the time to write a client to test the server. Yeah. So for lazy people like me, this is perfect. Or if your job is to just to write the API, why do you need to write a client? Yeah. And I don't want to spend weeks building out my unit tests. And as I'm showing here, it's really easy to build these unit tests and use these built-in client and servers. OK, so let's go on to our next piece of code. And I'm going to come in and maybe I misspelled. OK, let's fix this for the web hosting builder. So this just comes in and it's under hosting. So this constructor that I just brought in stands up and creates the server and the client properties. So what we're saying is server is a new test server. And we give it a new instance of web host builder. And what we give that web host builder is we call a use startup. And if you take a look, that startup is actually the class from our web API project. Right. And because that startup is what ASP.NET uses to stand up and get all your services and everything up and running for your ASP.NET project. And then the client is a client that's generated off of the server because the client needs to know everything about the web API. Right. And the server knows all about itself because it actually has its API internally. So we generate that client. And it already knows all the calls that it can do. So we don't even have to stand up and tell the client, here are all the APIs, here are all the verbs that go along with those APIs. And here's all the parameters that you can call. It just stands it up and we're good to go. Cool. OK. So the next piece of code is our tests. Now I'm going to bring in the first test and walk through that. So here is a test and we're going to fix this. So it references xunit. OK. And we need to fix that because HTTP status code uses system.net and task uses another reference. So we're all good. So OK. So this first test is we're going to test to see if we get the entire payload returned back to us with all albums of the all album API call. And you can see that in here we have inline data, which is a xunit attribute that we can decorate this test with. And we give it the verb that we're going to use. And that gets sent in to this method, which it gets used with this HTTP request message creator. And so this message, this request message, has to know two things. It has to know the verb and the string that gets sent over. And that string that gets sent over is api slash api slash albums. Because the client already knows the base URL. It's localhost colon some port. All we need to do is give it the segment that's different from the base URL. And that's just this slash api slash albums. So that's our range part of our test. Now we need to act on the test. And what we're going to do is take that request and we're going to send it through the client to the server. So we say undersword client.send asynchronously the request that we just created. And then we're going to wait to get the response back from our test host, which is running our web API project. And then down in our assert, we're going to first say that we want to ensure a successful status code. So a successful status code is, I'm quizzing you. What is the status code? What's it OK? What's a 200? 200, yes. I set you up with a softball. So we're going to make sure that that response gets back. Can't wait to see the hard ones. Yeah. So we're kind of doing a double assert. I want to show two different ways that we can check to see if that return status code is successful. So you can use response.insureSuccessStatusCode. And then you can say assert.equal. And then you can just say the response status code is equal to OK. And what you're testing here, you're not testing the data that comes back. I can. You can, but you're not doing that here. In this simple test. Right. You're just saying, if I call this, will it tell me it worked? Yes. And this is a simple test. So I could make more advanced integration tests. I could say, and we'll take a look at that. Yeah, but without this, this is so cool. Because you don't have to go to the browser and start typing things, which then every time you do it, you have to go to the browser and start typing things. I've also done this in Fiddler. Again, you can go in and enter the URL string, whatever, in Fiddler and see that it worked. But that's kind of a one-off. Here, it's more permanent. You can run these integration tests over and over and over again. Yeah, and I can load all of these tests up into continuous integration servers. Totally automated. Yeah, I can put in my local servers. And it can be run every time, anytime someone checks in code for this web API solution or project, all of these integration tests can be run to make sure if I hit this from the outside, are all my APIs correct. And if something blows up, I'll get an error code back with some kind of message. And that will alert someone. And then it should break something running some unit tests also. So I can say, oh, well, calling all albums broke. And then also, here's where I think the unit tests that failed correspond to that. And you can also, as part of the integration test, pass bad data and confirm that you get a, not a 200. Maybe a 400. A 400 or something. Yeah, you can test it when you call it incorrectly. It doesn't work. I can test it for anything. I can test it for the 300 level response codes. I can do whatever I want. Very cool. OK, let's take a look at one more unit test. And this one is a way to send over an additional property into your test. So you can see up here, I have an inline data. It's using the get verb. And I send over a 1. So that 1 corresponds with an ID on this method. And so I just say ID equals 1. And then I build my HTTP call string to use that ID. So I say slash api slash album slash whatever I send in for my ID. And I go through the same thing. Now, I could set up an assert that checks to see if the ID that I sent in through this method equals the ID that I get back from the response in the JSON payload. I could check to see that, too. Yeah, but you more likely have that be part of the unit test of the code, right? I could. I could test because my unit test will also, if I build all my unit tests right, I'm calling all of those controller actions individually in unit tests anyway. So all I'm really testing here is to make sure that if I ping something from the outside, that it's working correctly. So the integration test is this a correct statement. The integration test will typically lean in more towards assuming that if I call this service, right, I'm assuming that it runs correctly and it's been tested correctly, it's going to send me stuff back. Am I getting back what I expect? Yeah, and then to make sure that the service itself does the things that are correct, it's really kind of the service is job to do that, the person that wrote that. So you might, I would expect the unit tests on the service to cover that and this integration test to cover what happens when I call the service from the client. Well, and it's not written in stone. So think about, I build it so that every layer from the external API point back. So controllers and then maybe some middleware and then going all the way back to my entity framework core repositories that actually are doing the call and the retrieval of data, which then gets sent forward. Everything is being tested. So everything should kind of ripple forward. And if something breaks, it's going to break all the way. If something broke all the way back in my entity framework core layer in my data layer using my repositories, it should break all the way through. So it just will prove that it does break or it breaks somewhere in the middle and I can see where along that path it broke. But I just wanted to show, because a lot of times people have never seen this type of testing, this integration test. And you can add integration tests for the put, post, and delete as well. And it's actually working with the real live data? This is, but you can set it up. You could mock it. You could mock it in the back end too. You could set up in the other API. Which you probably want to do if you're going to run. So if you're going to run integration tests on CI, every time you check in code, your unit tests run, of course. And then your integration tests run. And part of what, or even in your unit testing, you're inserting, updating, deleting into the real database. You probably don't want to do that as part of your test. Especially since you don't let anybody delete from the database. So you'd have a bunch of bogus records that are in there. Or I have a bunch of records that are turned off that I would have to go back in. So you'd either mock or you'd be able to flip back and forth. But you'd have to put in a test database, which might get emptied out and redone, although there's overhead with that. Or you might just mock it. But that's the beauty of all this. You can do what you want. So for this test, I'm just showing how we actually do the integration test. And we're just going against the local database. Cool. So it's one more tool that you can put in your tool belt. Yep. Or your tool box. Or your tool box. Yes. In your Visual Studio tool box. Exactly. You have another testing tool. Yes. Right on. Cool. So we're now two out of three done. In episode three, you're going to teach us some best practices on how to do this better in real life. Hopefully. That's my goal is to show all the scars I have and what I do. Excellent. OK. All right. We'll see you next time on Visual Studio Toolbox. Bye.