FREELessons: 22Length: 5.5 hours

Next lesson playing in 5 seconds

  • Overview
  • Transcript

5.1 Testing the Post Functionality

With our code written, the final step is to test the application to see if everything works. We'll start by testing the post management.

5.1 Testing the Post Functionality

We're finally to the point where we can start testing our application because up until now everything has just been an exercise of theory and we can do some of these things with unit tests, but I'm also one of those types of people that like likes to run the actual application, so that we can actually see that the application does what it's supposed to do. So, we're going to start by creating the post, because everything hinges upon having a post within the data base. If we need to edit and delete a post, we of course need a post there. If we're going to edit and delete tags, we also have to have a post there. So let's get started by going to our solution explorer, and let's open up the _PostLayout page because we need a way of navigating between the different parts of our post administration, so that's why we have this layout page so we can do that, and then all of our pages within the post controller can use this layout page. So let's first add a link that's going to take us to our post creation form. So we can use the action link method on our HTML helper. We need to specify the link text, which can be Create a new Post. Then, we need the action name, which is create. We also need the controller, which is post, and then the area and we do that inside of an anonymous object. So we set Area to admin. And let's run this. Let's see what we get. Well, we first of all get an error. So, let's see what that error is, post controller already defines a member called delete with the same parameter types. Now we've seen something like that before and all we did was another parameter to one of the methods, and that's what we will do with the delete method that handles post requests. Let's just add a string called foo, then we can run it, and hopefully everything is going to work there, and it does. Our application builds, and we can go to admin/post, and we need a view for the index action. So let's go ahead and let's stop. And let's go to our post controller. Let's add a view for the index action method. So let's right click on the method. We want to add a view. It will be called index. For the template, we can go ahead and choose list because this is going to display a list of posts. For the model class, that is going to be post. This is not a partial view. And for the layout page, we definitely want to use our underscore layout page. So we can click on add. And that is going to give us a page that will display all of our posts. Now, this automatically gave us a link for creating a new post. Let's comment that out because we already have that, and now let's run our application. So we should be able to go to admin/post, which is basically what we are doing here, and we can click on create a new post, and here's our form. Now I notice that we have this date created field, and really this isn't something that should be editable. Whenever we create a post, we need to set the created property to the time and date that it was created, and then we should leave it alone. So really we should remove this field from our form. So let's go to Visual Studio, let's go to the view that has our form, which is _postform, and then let's just get rid of that field. We don't even need to make it a hidden field, because once we set the created property, then we are going to leave it alone. So let's take that out of the form, we can go back to the browser and refresh, actually, we can do that from inside of Visual Studio because a browser link. So we can hit this refresh button at the top here, and that will refresh Internet Explorer, and now the created date is gone. Now we do need to address that from inside of the controller, and we have two places where we can do that. Actually, now we only have one. I was going to say that we could do that inside of the creates method that handles get requests. We could set the created property there. But since we no longer have a field inside of the form, then really the only place that we can set the created property is inside of the create method that handles post requests. So after we go through all of this stuff here, we need to set model.Created equal DateTime Now, and that will take care of the created property. So, let's run our application again. And we want to once again go to admin/post/create. Or if you wanted to you could go to just admin/post and then click on the create link, but since we already have this URL here. So let's set the title to first post. Let's leave this log alone, because this should automatically be populated by whatever we specified within the title. So the content, this would be the first post content, the date published we can leave as null. And then tags. Let's do tag 1 and then tag 2. And then let's click on the submit button. Actually, let's set a break point. So let's go to our controller, and for the create method that handles post requests, let's set a break point on the first line inside of that method, so this if statement. So now let's hit the submit button. We will hit that break point. And the is valid property on our ModelState is true, so we can just step on through. We check to see if the idea's null, which it is going to be null. So then we set ID equal to title. And then we made the ID URL friendly. So if we move the mouse over the ID property we can see that the ID is now first-post and the next line of code makes our tags URL friendly. So if we look at tags then we will see tag-1 and tag-2. We set the created property, and now finally we try to create this post inside of the database. So we can just step over that. We didn't get any errors. So that's really nice. So we can go and continue and that will take us back to the index view but we don't see anything here, and we should because we just created a post. So from our code, everything worked fine until we tried to create the post inside of our repository, so that is where our code is failing. So let's go to the create method on our repository. So, let's go to definition. That's not what we needed to do because that took us to the I repository interface. So we need to go to our data folder and then the post repository. And then let's find the create method. So we create our context. We check to see if one exists. If it doesn't, then we attach and, I bet you that's the problem. Instead of attaching, we need to add because, because attaching is for when you have an existing record in the data base. And in this case we are creating a new record. So let's add that there and, that should work. Oh! You know what, we also need to specify the author ID and for right now we have a user that we can use for testing purposes: we have that admin user. But we need the ID, so we need to go to our database. Now if you have the SQL Server installed, either the full-blown version, or express, like I do, you'll need to go to the management studio. But if you don't, then you need to go to Solution Explorer. You need to click on this show all files icon, if it's not already selected. And then you need to go to the app_data folder. Now whenever you expand that there will be a default connection .mdf or something like that. You can double click that, and then that will take you to the server explorer which will then allow you to basically look at the tables within the database as well as the actual data within those tables. So we need to find the ID for our admin user, so if we go to databases and then default connections, tables. We want to go to our ASPNetUsers table. Let's select the top 1000 rows, although we should just have one. And this is the ID for our administrator user. So, we want to copy that. And we want to go back to our post controller. And we want to set the author ID equal to that value, so here we will have model.AuthorId equals, and then that GUID. And so now let's run this again, and hopefully everything should work now. So we want to, once again, go to admin and post and create. And then we will just enter in all this information again. So First Post and the first post content and then for the tags let's just do tag 1. Whenever we submit we are going to hit that breakpoint that we still have there. So let's take that breakpoint off, let's hit continue. And now we are finally getting data into our data store. Now as far as the information that we display in this list, we will need the title. We do not need the content, we don't really need the tags, and we don't want to display the Author Id, instead we want to display the author name. We also don't need this Details link. But if you look in the lower left-hand corner, you can see that this is generating a URL that we need for editing a post, as well as deleting a post. So we already have that stuff there. So if we click on the Edit link, we get a 404. Now there are two reasons why we could be getting the 404. First of all could be an issue with routing. We might have overlooked something whenever we set up our routes, which we really didn't set up except through the attributes. The second thing could be that we are actually getting into the edits method. But our post is null. And this is easy enough to test. We can just set a breakpoint on line 83, and if we hit that breakpoint then we know that we are at least getting into the edit method. So let's go back to the browser. Let's refresh and we do hit that breakpoint. So routing is working okay. So let's look at what we have for the post ID. We have null. Okay, so routing is kind of working, but then it's not working, because the post ID from our route is not being mapped to the post ID parameter of our edits method. So, it's actually a combination of the two things that I mentioned. We've overlooked something as far as our routing is concerned. And our post is null because we are passing null to the guest method. So the first thing we should do is go to our global.asax file. Let's see what we have here. We have the area registration and then we have the route config. Now I know that because we are using attribute routing we actually need to put this area registration after we call the method that we need for attribute routing. And I don't remember if we called that method, so let's go to the register routes method, and this is going to tell us exactly what we need to know. No, we did not set up attribute routing, so we added the attributes to our controllers, but we did not actually enable that feature. So, to do that, we use Routes and then, MapMvcAttributeRoutes. And that should be it. So, the first thing is that we need to call this MapMvcAttributeRoutes inside of our RegisterRoutes method. The other is that we need to move the AreaRegistration to after enabling the attribute routing. So, that should work for us. Now, because we have specified that we want to use attribute routes, we definitely need to ensure that we have a route attribute for all of the action methods in our post controller. And I believe we do, except for the index action method. So we can add that route attribute. And in the case of index, we don't have anything in the path, so we can just have an empty string. And create has one, the edits method has one, and delete has one. Okay, so now we should be ready to go. So let's run this application again. We want to go to our admin, and then /post. And hopefully we will see our list of posts, and we do. If we click on edit that should take us to our edit form. We hit that breakpoint. Let's go ahead and see if we have a value for post ID, and we do. So let's take this breakpoint off, let's hit continue, and we should have our form. We do. And the fields are automatically populated for us, so we have first post and then first-post, and then first post content, the date published is still null, and we have our tags. Tag-one. So let's make some edits. Let's add something to the title. So edit. Let's leave the slug alone for now. Let's add something to the content, just to make it different, and let's add another tag to our tags. So let's click on submit. And everything works. Our edits for the title can be seen, the content is there and we really need to get rid of the content. So let's go to the index view and we can modify the columns within this table so we can get rid of the header for the contents because we don't need that. We don't need the combined tags, although were they there? Yes, they were. So we can get rid of the combined tags. Let's also change this header for the author ID. We don't really want the author ID. Instead we want the author and then we just need to remove the fields from the data portion of the tables. So we can get rid of the content, we can get rid of the combined tags, we don't need this details link so we can delete that. And instead of specifying the item.authorID we can say item.Author.DisplayName, and that will use the display name. So we can go back to the browser, let's refresh, and we will have a cleaner table. We have the title, the date created, the date published, the author, and then edit and delete. So now let's go back to the edit form, and let's make some other modifications. Let's try to change the id. So let's do first-post-1, and let's just leave everything else alone. Let's click on submit. And here we are right back at the form. So something did not work. Let's go to our controller and let's set a breakpoint inside of the edits methods. So on line 100 we will set a breakpoint. Let's click on the submit button. We hit that breakpoint. So let's just step through our code. The model state is valid. We have a value for the ID so we can skip over that. Let's get to our repository. So this we can step into. We can go through all of these lines of code. So far nothing is throwing an exception. Except whenever we try to save, and that is where we hit this exception block. Let's look at the exception itself. We see that the property id is part of the object's key information and cannot be modified. So basically, we cannot change the id. And, that's fine. But, we did not see our error message inside of the form, so instead of passing in the exception itself, let's pass in the message. I thought that it would take the message from the exception, but maybe that's not the case. So let's run this again and we will see if this now works. So, or at least the displaying of the error message works. So we want to go to Admin Post, then we will go to Edit, and we will edit the id. We will Submit, and hopefully we will see the error message. But we hit that break point, so we need to remove the break point. Let's hit Continue, and no error message. So the only other thing that we can do is specify an empty string here. So instead of specifying key, we use an empty string. And now, that will display. I thought that just using key would work because if we look at our view, let's go to our _postform, and then we look at the ValidationSummary method. You can see that the first parameter of this method is excludePropertyErrors and you can see that that is set to true. So by default, it's not going to display errors for the properties themselves. And since key is not a property, I figured that that would work. But, apparently it doesn't. So let's go once again to Admin and then Post. We want to edit that one post that we have. Let's change the id, and then, whenever we submit we should see our error message. And there it is. So as far as editing posts, we are stuck with whatever id the post has. And, that's okay. So, we can go back, and let's create another post. Let's call the Title, Second Post. Let's give this an id of second-post-1. And then for the content, second post content. We'll leave the date published alone, and for the tags, let's do tag 2. And then submit, that will create our post, and now we just need to test the delete functionality. Now right now we don't have a view for our delete action, so whenever we click on Delete for either one of these posts, we're going to get to this wonderful error. So let's stop running our application, let's go to our controller, and let's go down to the Delete action method. Let's add a new view called Delete. We'll use an empty template, and inside of the view we will add the @model declaration. And this will not be a partial view but this will use the _PostLayout as the layout page. So let's just take the defaults in add, let's add the @model declaration, and we want our post that is inside of our @model's namespace, and we could use the same form that we've used for creating and editing. That way we could see all the information, but really all we need is just the Title and then a button that says Delete. So we have this delete up here so we could just ad @model.title and then we just need a form. So add using var frm=html.beginform, and all we need is a Submit button. So input of type, Submit, and for the value, we can just say, Delete Post. Now, ideally, we wouldn't even make it to this view. We could click on that delete link in our post list and that would send a post request through AJAX and everything would be done there. But, it's always good to have just the basic functionality there in case if the user doesn't have JavaScript enabled. But this ought to be fine, because this is going to submit the post, although we do need the id. So let's look at the post controller, and let's see if the id is going to be part of the URL. And it is. So we don't even really need to send the id. So, let's run the application and we will make it back to our post list, so we want to go to admin/post and then we should be able to delete a post. Let's delete this first post and that will take us to our view. Whenever we click on the Delete Post, it should delete. Although no it doesn't, because we did not add the AntiForgeryToken to our view. That's easy enough to fix, we just need to go back to our view. And inside of the form, we need Html.AntiForgeryToken. And now, our code should work. So we want to refresh this so that we get that anti-forgery token, let's make sure that it's there, and we have the name of RequestVerificationToken. We do, so we can delete the post, and voila. It is deleted. Well we verified that our post controller and our post repository work. There are some things that I would like to do, like revisiting the edits method that handles post requests. Because now that we cannot edit the id, we really need to refactor that code so that id isn't even a consideration. But, that's really not pressing because the code works and we have protected ourselves. Not only is the database not going to allow it, but we also display an error message if we do try to change that id. So for right now, we're going to move on and start testing our tag controller and tag repository, and we will do that in the next lesson.

Back to the top