5.2 Testing the Tag Functionality
Now we test the tag functionality. As we're doing so, we'll have to make some adjustments to our code.
1.Introduction2 lessons, 05:56
2.Managing Posts3 lessons, 38:13
3.Tag Management2 lessons, 27:29
4.Storing Data3 lessons, 47:22
5.Testing Functionality2 lessons, 33:06
6.User Management3 lessons, 1:11:48
7.Security and User Authentication2 lessons, 34:17
8.Enhancing the User Experience2 lessons, 36:38
9.The Front-End2 lessons, 36:01
10.Conclusion1 lesson, 01:22
5.2 Testing the Tag Functionality
The process of testing our tag controller and tag repository is going to be very similar to what we did in the previous lesson. That is, we are going to go through the motions of editing and deleting tags. But in order to do that, we need some data to work with. So off-screen, I added a third post. There are two tags applied to this post. One is called tag-1. The other is called another-tag. And then I added a tag to the second post. And it is called yet-another-tag. So we have four total tags that we have to work with. So let's go to admin/tag and we will get started. Although, no we won't, because we have a 404. Now because we are getting a 404 for what is essentially the index, the only issue that could be causing this is the routing engine. We haven't done something correctly. And right off the bat, I can tell that we don't have any of the route attributes applied to this controller, so we need to do that. So we need the RouteArea and that is admin, and then we can also add the the RoutePrefix, and that will be tag. And then we need to add the route attributes to our action methods, so here for the index we'll have Route and then we will pass an empty string, because that is the index, that is the root, essentially, of admin/tag. But we can use that as the basis for everything else. For edits, we want edit/tag. And we essentially want this same thing for the other edit method, so we can copy and paste that. And then for the delete method we want the same thing, except that it will be delete/tag and we will use that for the other delete method. And while we're here, let's make sure that we have a default constructor. Since we didn't add the routing attributes, I'm pretty sure we did not add a default constructor. No, we don't, so let's add public TagController, and we want to call this and then new op a TagRepository. And that should get our code to work. So let's run the application once again, and hopefully we will see a list of four tags whenever we go to admin/tag. And instead we get an exception. Let's see, it says that the DbContext has been disposed. And we are getting this error down here whenever we enumerate over the model. So this is something that we should not be getting because I thought we had made sure that we enumerated all of the results before we returned it just so that we wouldn't have a disposed DbContext. So let's stop running. We need to go to our repository and we need to look at the GetAll method, because that is the method that was being called. We have db.Posts.SelectMany, and I guess what we can do is, before we call the Distinct method, we can say ToList, and then Distinct. So if we run this again, hopefully we should see our list of tags. But I'm also not sure because we used the tags property, and if you'll remember, I said that I don't know if this is going to work, so this is the moment of truth. Will this work or not? And no, it doesn't. Let's see, the error says that the specified type member 'Tags' is not supported in LINQ to Entities. Only initializers, entity members, and blah, blah, blah, blah, blah. So we cannot use the tags property. I see two solutions to this problem. The easiest thing that we could do is call ToList after db.Posts. That would retrieve all of our posts from the database and we would have that collection of posts in memory, so then we could process the tags using the Tags property, and then we can call Distinct and everything would work. The only issue here is that it would be potentially inefficient. For a few hundred, a few thousand rows, it's really not that big of a deal. But if we have 10,000, 100,000, or even 1 million posts, then yeah, that's going to be a performance issue. So this will work, but it's ultimately not the best solution. So the other solution would be to first of all retrieve all of our tags. So let's create a variable called tagsCollection, and we want db.Posts. We want to use the Select method, and we want to use the CombinedTags property, and we will go ahead and call ToList so that we get all of our tags. Now each element in our tags collection is going to be one or more tags. So let's say that the first element is going to have tag-1 and then another-tag. And then the second element is going to be tag-2 and then yet-another-tag. We want to take this collection and transform it into a single string. So we want to essentially do this, but we also need to separate each element in the collection with a comma so that we have tag-1, another-tag, tag-2, so on and so forth. Well, we can easily do this with the string.Join method. So we could do something like this, string.Join. We want to join this collection using a comma between each element in the collection. We specify our tagsCollection. And then we want to take this string and then split it on the comma. And that is going to give us an array where each element is an individual tag. So we call Split, we specify a comma and then we call Distinct. So now if we run this and whenever we go to admin/tag we should see our list of four tags. So here we have admin and then tag, and voila. Now in order to ensure that the distinct portion is working, let's go to admin/post. And let's go to the second post, and let's add a third tag here. Let's add tag-1. That is a tag that is on our other post. So let's Submit that edit. Let's go back to our tags, and we should still see four tags. And we do. Now before we do anything else, let's go back to our repository because we used the Tags property in each one of these methods. And since we can't use it with entity framework, we're going to have to adjust our code. So inside of the Get method, we need to change our code where we are using this Tags property. And of course, the easiest thing that we could do is call ToList after db.Posts, but we know that that will eventually be very inefficient. So instead, we can use our combined tags property. So db.Posts, and we will use the Where clause here and Where post.CombinedTags.Contains the tag that we are searching for and then we can call ToList. Now this search is not going to be accurate, because let's say that we are doing a search for the another-tag tag. Well, that's going to work for this particular tag, but it's also going to find a match with yet-another-tag. So we're going to have to whittle down our posts here based upon our tags, but we are already doing that. In fact, this will be pretty easy. We can get rid of the var here. We can say posts = posts.Where, and then that's where we use the Tags property to ensure that the post has a given tag and not a tag that contains that tag. So that's actually going to be a pretty easy change, and we have this same logic in all of the rest of our methods. So if we go to the edit method we can paste that code in. Now we do have a different variable name here, so we can change Tag to existingTag, but that's really all that we need to do with that first statement. Then we set posts = posts.Where and then we use our tags property. Then we do the same thing inside of the delete method. So let's copy that code, let's paste it in. We need to once again change existingTag to Tag, but then we will say posts = posts.Where and then we use our Tags property. So that should work. I'm not sure, but the logic to me is sound. So let's run the application. Let's go to admin and tag, and let's edit tag-2. And it's trying to find a view called tag-2. And you know why that is, it's because our controller, we're passing a string to the View method, and so it's going to try to use the value of that string as the view. So basically we need to say that the string value that we are passing to view is actually the model. So hooray for named parameters. So we basically say that model is our model. And we will do the same thing down here. Model is Tag, and model is model, and that's it there. So now we can run the application and everything should work now. Hopefully everything should work. My fingers are crossed. So admin/tag we have our lists of tags, let's edit tag-2. Hurray, let's change tag-2 to tag-3. Let's save it and now we have tag-3. So let's go look at our posts. I'm going to fire up another tab and we're going to go to admin/post. And that was on the second post, I believe. So if we look here, we have yet-another-tag, tag-1, and then tag-3. Now, let's delete tag-3. So we will delete that, and a Boolean of foo cannot be null. So that's easy enough to change, we just need to change that from a Boolean to a string. So let's click on the Delete button again and sure enough, tag-3 is gone. Now let's look at our second post and we only have two tags, we have yet-another-tag and tag-1. So since we have two posts that have tag-1, let's edit this and let's see if the change is made for both of those posts. So let's call this tag-1-2. We will save it and we see that change here in our list. We can go to editing of our second post. Let's refresh and here we have tag-1-2. Let's go back to the list and look at the third post and our tags should be changed there as well. So our tag controller and tag repository both work as well. We had to make a few modifications, but overall it was relatively painless.