In this Capstone project for the Photo Tourist you will implement a Ruby on Rails web application that makes use of both a relational and NoSQL database for the backend and expose the data through services to the Internet using Web services and a responsive user interface operating in a browser from a desktop and mobile device. You will have a chance to revisit and apply what you have learned in our previous courses to build and deploy a fully functional web application to the cloud accessible to your co-workers, future employers, friends, and family.
In developing the Photo Tourist web application, you will get to work with different data types and data access scenarios (e.g., fielded data display and update, image upload/download, text search, access controlled information) to provide your users the ability to show off their photos and information from trips they have taken and to seek out photos and information from trips taken by others. Using the application you develop, your users will be able to
• Create an account
• Upload and download photos to the site and make them accessible to others
• Provide descriptions of trips and photos that others can read
• Organize photos by location and trip,
• Find photos based on location
• Find photos based on text searches of descriptions
• Locate the place where the photo was taken on a map

Reviews

EA

Great Course Jim has really thought me more than enough to get my career started. All a student has to do is just study.

KT

May 04, 2017

Filled StarFilled StarFilled StarFilled StarFilled Star

Excellent course. Mr. Stafford is a very good teacher.

From the lesson

Testing

In this module, you will learn how to development model, request, and feature specs using RSpec and to leverage gems like DatabaseCleaner, FactoryGirl, and Faker in building those specs. You will also learn how to DRY their tests using RSpec shared_contexts and shared_examples as well as Ruby modules for helper methods. All use of tests within the capstone will be "integration-style" tests, going to the database and back. We will not have time to implement pure unit tests for individual components. For model testing, we will focus tests on factories, query scopes, relationships, and facade methods interacting directly with PostgreSQL and MongoDB databases. We will address the general purpose and custom techniques for managing the database state during cleanup. For API testing, we will form a hefty set of RSpec shared_contexts and Ruby helper methods for the request specs that will take care of the details of many CRUD behaviors and other tedious, repetitive tasks. The API is not only easier to test than the Web UI, it is a first-class external interface deserving of separate testing. During test coverage, you will learn internal Rails error handling techniques that will provide the web client a proper and sane web reply in the face of errors. For Web UI testing, we will introduce Capybara for building feature tests and the role of the RackTest, Selenium, and Poltergeist/PhantomJS drivers for implementing UI testing with Javascript. Although Capybara provides a nice interface for expressing Web UI tests, the asynchronous nature of Web UIs make them extremely difficult to test without well thought out decisions during development. This course has a special emphasis on teaching you how to develop automated integration tests at all levels of the architecture, including the Web UIs. It is recommended that you review this module and sample further test-related lectures in follow-on modules to get a good understanding of how testing can best be leveraged in a full stack development (within constraints of the course). Except for the seasoned RSpec and Capybara user, there is no shortcut through this module.

Taught By

Jim Stafford

Adjunct Professor, Graduate Computer Science

Transcript

[MUSIC] In this lecture, we will discuss testing the API Create method. And like before, it's not the testing that actually makes up the bulk of the lecture, it ends up being fixing the things that the test finds. We will re-encounter the wrapped parameters problem that we encountered a while back with the angular client. However, this time, let's fix it on the server side. And then when we're done, let's take a step back and see what we can dry with our test and move to our API module. Okay, to get started with creates, one of the first things we're going to need to do is to get some data. So what we're going to do is take advantage our Factory and use the attributes_for. We can take a look at this function down in our rails console and see that we're going to get back a hash with a name property and a name value. Of course we need to turn our example into a block so it gets out of pending state and then we're going to issue a post. At this point in the discussion, let's kind of treat it like a get, it's a function that we're going to call and that we owe it a path. We're going to send it to the foos_path without an ID. And we're going to send it this document to_json, and we can take a look at that in the rails console as well. And that's going to turn that into a string. And then with it in that state, we need to tell it its content type, that we're passing it application/json, okay. Now when we inspect what comes back, we expect it to be a created, a 201. And we expect it's going to echo back what it created using a json document. That's enough to get started. Why don't we go ahead and run that with some debug. Dag nabit, a guy can't catch a break around here, can he? All right, if you remember back, there was a problem with our angular talking to our backend, where we had to change the structure of the document. We couldn't just post a naked foo with all just its attribute, we have to embed it below of foo element. And if you remember what this document look like, it referenced foo nowhere. It was just its naked elements. And the way we can tell that we were getting this kind of error, is we can look in the log. Now, because I ran rspec within the pry shell, within rails console brought up in the development profile, actually ended up accidentally using the development database. No big deal. Just know that can occur based upon what your profile is when you go into the rails console. So what we have here is that the parameters did come in, name, Destany in this particular case. And it's saying it's a bad request, it's missing a foo. Hm, okay, well, what we could do is do exactly what we did with angular, and fix it on our side. But why don't we use this as an excuse to fix it on the server side, okay? So that means we're going to have not only a trip to the controller, but we're going to have a trip to the server. So let's exit our server and go into a file that does exist, wrap_parameters and what we need to do is uncomment out this block. And because we're using the rails API, I need to add this other option. I won't go into it in too much detail but essentially what this is doing, this will allow the server to compensate for having naked parameters come into the server and what it'll do is it'll automatically copy the ones that we specify to go below a parent document. Notice what line 8 is saying is implement wrap_parameters with a format of json if the controller has a method on it wrap_parameters. And we will need to do that. So we'd save that off and restart our server to make it available at runtime, although our tests automatically bring up a new server. And then we need to go into the controller. And then in its simplest of forms, we could just do this. Were what it's going to do is, it will inspect the foo class and see what kind of properties it has. And then if it sees properties by those names, it will then create a new element called foo and copy those elements below. A longer hand form of doing exactly the same would be to say foo with these parameters. And that actually isn't a bad idea because it keeps us some junk from being copied down. Let's say if our client supplied ID, or created ad, or updated ad, we should ignore those properties. They don't need to be copied. Okay, now with this in place, I should be able to run my test and pass, okay? And if we take a look at the log, we should notice what we did. So what we passed in was {"name"=>Clovis Yundt", and what the server did is it created a :foo=> element and copied down name, because we asked for name to come down. If we would have passed in a abc parameter, only name would have been brought down because we said only include that here. And we will get trash from the angular client, and it'll be through laziness. We're managing particular information and we store it with a resource and it ends up going over to the server. So this actually is kind of nice to clean things up, okay, wrap_parameters. All right, so as we finish up, let's take a look around and see what else we could dry. What I'm going to do is point out line 56. This becomes annoying, to constantly have to say I'm passing you to application json, to have to call to_json on it. Why don't we create a helper method that does a lot of that work for us? And let's go ahead and put that in the API helper module so that it's available to all of our request specs. So to get started, let's take this function and go to our API helper module and begin to form a method. We're going to do this in waves. The first implementation isn't going to be our final, so let's try to keep things concrete. So what we're going to do is we're going to start out with a jpost. The built in method is called post. We're going to make ours jpost and the first thing we're going to owe is a path and that's what this will be. And the next thing that we're going to need are the params. And if there are no params, we ought to account for that, that they should default to an empty hash. So foo_state is going to be params. Now we should also allow for other headers to be passed in and default that to an empty hash. And then I can make up the parameters to the method. We're going to be able to call post with the path provided, with params they provide, convert it to_json, and the headers merged with our application json content type. All right, that's a decent start, so let me go back to my test and make this jpost foo-state and I don't need to supply anymore. Let's give that a go. Come on, you sat there and didn't see anything. I missed a open parent after the post and between the path. And let's give that a go. Okay, nice work. All right, many more improvements to make to this method but without going overboard, let me just stop with this one more improvement. It's fairly concrete. There can be times where we post to our URI without passing a payload, so we only want to say that we have application json in the headers if there's a params. So if the parameters end up being empty, then we don't want to add a content type, so we just zap it from here. And we also don't want to change their headers, so we create a new one. Okay, that'll hold us for a little bit. So in summary, our create testing discovered some errors. And actually they were errors that we had seen before with our angular client, with wrapped parameters. So rather than fixing it within our tests, we went over to the server and re-enabled some settings that were disabled by the rails API. We noticed that our post method was getting a big verbose. And so we've created a helper method in the API module that simplified our existing test. What's next? Well, let's continue our testing, see what else we can find with update and delete.

Explore our Catalog

Join for free and get personalized recommendations, updates and offers.

Coursera provides universal access to the world’s best education, partnering with top universities and organizations to offer courses online.