 That is my Twitter handle. You can follow me on Twitter. I'm not much active. I just retweet tweets, but yeah, you can still follow me. I work for BigBinary. We've already told you a lot about BigBinary. We mostly work on Ruby on Rails and ReactJS. We also work on React Native. So if you want to talk about any of these, or if you just want to talk about anything else, then catch on later. I flew from India. I stay in Pune. It's a beautiful city. A lot of people here were talking to me and they were saying that we like Indian food. So if you want good Indian food, you should definitely come to Pune. And you'll really like it. And we also have a Rubycon. So Deccan Rubycon. This is the third year of this conference. And if you need another excuse for coming to Pune, this is another excuse. So we have our CFP open. If you want to talk at this conference, please submit your talks. You can also get more information about it on DeccanRubycon.com. I'm also part of Rails issues team. So one of the responsibility of being part of Rails issues team is to go through all the issues and try issues, like comment on issues, whether they're valid or not. We also have some superpowers. So we can close your issues. So if you feel that your issue is not valid or it is not good, then we can close it. But you have to trust me because I have only pasted the close box. There is no mention that this snapshot is from Rails repository. So trust me. I also maintain this site cotrial.com. So if you want to get involved into open source and start contributing to open source, then if you're subscribed on this site, it will send you a daily email with all the issues from your favorite repositories from GitHub. And then you can go through those issues, comment, maybe try to fix those issues. So if you want to get involved in open source, please check out this site and open your account. So generally when speakers give talks, they always mention that they have some stickers to give. But I don't have any stickers to give because I'm a bit different. I like to collect the stickers. So this is my laptop, right? If the people sitting in the front, they can see my laptop, there are a lot of stickers. And I like to collect stickers whenever I go to conferences. So do you have stickers? I like them. So if you have stickers, come to me and give those stickers to me. I also like t-shirts and other sacks. Everything is fine. Thank you. But even if I don't have any stickers, I have something for you. So if you have any favorite open source contributors and if you want to say thanks to them, then I have some postcards for you. So these are those postcards and you can write a message here saying thanks to your favorite open source maintainers and you can catch me later if you want some of those. And this is the idea of Richard Schneemann who was here I think two years ago for the first Rails specific. So you can tweet to him and say thanks to him also. Okay. So that was all the jokes. That was all the funny stuff that I wanted to talk. Now let's get to serious business. We will talk about all the secrets of testing Rails 5 apps. First of all, I will tell you the biggest secret of testing Rails 5 app and delete all your tests. That is the biggest secret. Then you don't have to worry about running your tests at all. Just delete them. Okay. I'm just kidding. This is not the actual secret. Now all the jokes are over. Let's get to serious business now. So what is important in testing? So when we write tests, that is important. We should write efficient tests. And then while we are running the test, that process should also be efficient. We should get proper feedback of our failed test. That process should be fast. And that feedback process should be in such a way that we can maybe reuse that information to run test, fail test efficiently. So in this talk, we will talk about both the things. We will talk about how things have changed related to running the tests in Rails 5. And we will also talk about how things have changed related to writing tests in Rails 5. First of all, we will talk about running. Now when running the test, as I said, feedback is very important because testing is an iterative process. So we don't do like this. Like write tests for first three days and then on Thursday at 10 a.m. after getting a cup of coffee, run all the tests. We don't do like this. Testing is an iterative process. We write few tests, then some of those tests fail, then we write some code for those tests to make them pass, and then we run those tests. And before Rails 5, how we run our test was using the right test. And this used to run all the tests in our test directly. But we are concerned about the output of the test. So whenever some tests fail, we want to see what exactly, why they failed or what was the exact reason of the failure. So test output matters a lot. And once we start writing this test, we also should have the ability to run this test again and again and again because we are always writing some tests and some of those are failing. It's not like we write all the test and then everything passes. That is not at all true. Some tests will fail. So there should be ability to run selected tests from our test suite. There should be ability to run multiple files at the same time for a good testing workflow. The test output should be in such a way that we should be able to, like if we pass that output again to the test runner, then it should be able to run the test for a good workflow. So let's see how we used to do it in Rails 4. This is a simple controller test and it is failing right now. Rails is telling me that this test is from the user's controller file from line number nine. So yeah, okay, I can understand this information. As a user of this library, I can say that, okay, I know what is happening. Some test is failing from this file from line number nine. Okay, I go ahead and fix the test. And now I want to only run this test because let's say my test suite has 3,000 tests. If I rerun all the tests, then I will spend five minutes in it. So I just want to run this test. Then I try it. I just copy paste that line and try to run it on the console and it fails because Rails is not able to understand how to pass this information. So if it was able to pass this information, then my workflow would be better because I would not spend a lot of time in figuring out how to run a single test or in running all the tests. So what I expect from this test is, I expect that it will show me what exactly failed. It should also show me that quickly. I don't want to spend too much time in figuring out what exactly failed if I have a very large test suite. Ideally, if possible, it should also tell me which tests are slow so that I can improve on those tests. But again, this is not really, this is nice to have feature extra add on. Even if it is not there, it is fine. But currently, we don't have any of these features. So if you use the default Rails test stack before Rails 5, you don't have any of these features by default in your Rails application. But if you ask somebody, they will always say that it is possible. You should try more. It is possible because it is ultimately Ruby. It is based on the Minitest library. So if you know some of the internals of Minitest, how to pass arguments, if you know how to use environment variables with your rake task, you can do this. You can have all of these features, like how to run a single test and everything. But the real problem is discoverability. How a new person who starts with Rails, how he can find very easily to run a single test or to rerun multiple tests or to run a test from multiple files. If I run a search on Google, I will find thousands of results. But instead of that, if this common feature was baked inside Rails, it will help everyone. Another issue is related to documentation. Generally, if you see all the Rails command tasks, they are very well documented. But if you see the test task, there is not much documentation. We just see that, okay, we can run all tests. We can run all tests quickly and okay, there is nothing much I can get from this documentation. Compared to a simple Rails command, this gives me a lot of documentation with all the options. And it is very detailed documentation. So compared to this, the test output documentation is not very good. Also, many libraries are trying to solve this problem because they are very common problems. There are a lot of solutions that are already available. So there is this Maxi test library which tries to solve the same problem. So it provides all these features with some other features which are not part of Minitest. Then there is MTestRunner which allows you to rerun your snippets by line and everything. So there are a lot of tools. So people recognize this problem. This is not like only few people are saying it. People recognize this problem and they are trying to actually solve this problem. So what Rails team finally decided is enough is enough. Now in Rails 5, we should make our running test great again. So that was their main motivation. And DHH also approved it. So if you can read this, I'm not sure it is readable again. But what he is trying to say is many libraries are trying to provide same solutions. So instead of that, we should just have it everything in the Rails. So that's why Rails 5 has this TestRunner feature. So it will ship with TestRunner which will have all of these abilities. Now when you create a new app in Rails 5, instead of running your test through rake task, you will have a new command for running the test, bin Rails test. And it is a proper executable. So it can accept some arguments. It can parse those arguments. And it can infer whatever information we are passing to it properly. So this is the simple example of running our test in Rails 5. We just do bin Rails test and it will show you like whatever, 7 runs, 12 assertions, 0 failures, and everything. So this output doesn't tell us much right now, but we will see how it is improved than the rake test runner we had before. So we discussed before, right? We need proper documentation. We need to know how to run test. And we should know all the options that are available that our test runner is able to accept. So if we just do bin Rails t-h, it will show us all the information. And this output is almost similar as what we saw earlier from Rails new command. So, yeah, it is improved a lot. You can see specific things like how to rerun your snippets. You can just pass the file name, line number, and it will run that test. You can also see some Rails specific options like if you want to set some environment, if you want to see backtrace, if you want to fail fast, all of these features are now available by default. And then you can also pass some many test specific options. So you can set the seed, you can set the test output to be verbose, and a lot of stuff is there. So this test runner improves the filtering of tests. Now it is able to pass the test correctly and only rerun those tests which are failed or only rerun a test from which files, from the files which we want to run. And yeah, rerunning the test is not possible, now possible. So if I just pass that command, and this indicates that I want to run the test from line number 18 of my post controller test file, and then it will only run that file. So if you see at the bottom, it is saying one run, one assertion, one failure. So it has not run all the test, only one test is run. And it has also printed the command for me, which I can use when I want to rerun this test again after making it pass. Running multiple tests is also possible, we can just pass different file names and it will properly infer it. We can also pass different directories. So if your code is dependent on your models and let's say your controller code, you can run all the tests from those separate directories also. Another good feature is improved reporting of failures. So reporting is very important because it can tell us a lot of things, like I discussed about getting information about slow tests. So if we have a custom reporter, then that reporter can store the time required for like how much time it was taken by your test and it can show us the slow test at the end. So Rails test runner also ships with a lot of features related to report, like having good failure output, like fail fast, you can just pass minus f option and it will show you, it will just stop after the first failure, it will not run all the tests. You can see the backtrace. So by default, Rails uses its own backtrace. It doesn't tell you what, it doesn't show you the whole backtrace of your exception. It shows you the trimmed down version. But sometimes it is needed, like the error is coming from some other gem. Then you want to see the whole backtrace. And in that case, you just have to now pass minus b and it will show you the backtrace. You can also see the third output. So if you want to see all the failed test output at the end of your test run, you can just pass minus t and it will show you the output at the end. We also see colored output. So this is the most important change because colors are nice. So now if we run the test and if some of the tests fail, we will just see the output in the red. And if the test passes, we will obviously see it in green. That emoji is not coming from Rails. I just passed it. Okay. So all of these features are actually coming from Minitest. As we know, Rails test pack is based on Minitest library and it heavily uses Minitest 5, which has a plugin architecture. And using this plugin architecture, Rails is able to hook into the Minitest testing library and provide some top-level filtering capability and reporting capability. So for filtering, Rails has written a Minitest plugin and then they have a custom reporter for showing you all the colored output fail fast and other stuff. Now you must be wondering, right? If I just use RSpec, then I don't have to worry about any of these. I already have all of these features in Rails 4 also. So obviously, yes. Nothing is new here. Everything was there in separate libraries. But now it will be part of Rails 5 as a default stack. So it got inspired from these libraries like RSpec, Minitest reporters, Maxitas, M, and a lot of other libraries. So now the good thing is it's just part of Rails. So you don't have to install any of the gems. Just install, just create a new Rails app or upgrade your existing Rails app and you will get all of these features for free. So this was all about how things have changed related to running the test. And now it is time for a break. So yesterday, we had a lot of food. We had durian, stinky tofu, and a lot of other food that can't fit in in this slide also. So thanks, Junito, for giving us a ride in the night market. The food was really great. Okay. So now we will talk about the second part of the talk. We will talk about how to exactly write tests. And there are a lot of changes related to how Rails is recommending us to write our tests. So we'll discuss all of those. Now, if we consider Rails tests, there are three parts like unit test, functional, and integration test. There are not changes in unit test at all in Rails 5. So they will continue to work as it is. So there is no need to worry about them. But there are a lot of changes related to our functional and integration test. So we will discuss those in more detail. Specifically, we want to discuss controller tests because functional and integration are sort of like they lie on the boundary of controller tests. So we want to discuss controller tests in more detail. Now, many of you must have written a lot of controller tests. What do we actually test in a controller test? What do we actually test? So what do we actually test is we test the request, the incoming request that the controller receives, and then it renders some response. So the output of the controller is the response that is rendered. And that's what we test. We test whatever the response that comes out of that controller action. So this is the typical test case for Rails 4. And as we can see, we are just making a create request for creating an article. We are passing all the params. Then we are verifying that it got redirected to correct article path with whatever article that we passed. But one more thing that we are testing here is asset difference article count. So I said that we only should test whatever comes out of that request. And whatever comes out is the response, which got redirected to some other page. But it also allows us to test these side effects, like how my database was changed due to this particular request. So we don't really test the actual response, but we actually test the state, whatever state that was affected by this particular request. And this state can be anything, like it can be the controller's response, but it can also be some database related changes, like you added one record or you removed one record. The beauty of controller test is they're very easy to write. You just do like post create, pass the params, and everything works as it is. And they're comparatively fast also. So writing them is also fast and running them is also fast. But they have a problem. They actually lie. Now what happens in the case of these functional controller test is Rails sort of bypasses the actual request flow. So if you consider a normal request, what happens is the request comes, it hits the Rails application stack, then the routing gets involved, route gets passed, then it passes that to controller action, and then the response gets generated. But in case of functional controller test, this request flow is not followed. So what here Rails is internally doing is it is directly calling this create action. So there is nothing involved related to how this request gets passed by a router, nothing. Just call the create method from my articles controller directly. So it doesn't follow the normal request flow. And that's why they sort of lie. So if your code is dependent on some middlewares, your functional controller test will not be able to understand that code because no middlewares are involved when running this test. And that's where integration test come into the picture. Because they go through all the middlewares. They follow the same, like they stimulate the same process that happens when we make the actual request to our Rails app. So this is a simple integration test which does the same thing, creating an article. But instead of hitting the create action, we are actually hitting the article's URL. So we are actually hitting that path slash articles. And we are passing the parameters. And then we are asserting the same thing, whether it got redirected to article path or not. Now if you compare this with the earlier controller test, functional controller test, both of them look exactly same. I mean not exactly same, but almost same. We are testing the same thing. We are testing whether you got redirected to a new article or not. We are testing whether the article count was increased or not. And we are testing the same path. We are sending the request to slash articles. So they are almost same. And one more good thing about integration test is they are close to real wide. Now because they simulate the exact flow that happens when a real request hits Rails app, it's good to have integration test rather than controller test. Because then you are close to your actual production behavior. But the only problem with integration test is they are very very slow. Actually in Rails 4 they were very very slow compared to running your functional controller test. And that's why many people preferred writing functional controller test over writing integration test. But in Rails 5 that is no longer true. So a lot of work has been done in last one year to speed up integration test and make them as fast as controller test. So now when you run integration test in Rails 5 and if you compare the time taken by it with equivalent controller test, then you will find that that time difference is not much. So they are comparatively same as they have same speed. So now there is no like there is no need to maintain and no need to have a functional controller test. We can just have integration test by default. And that's the default in Rails 5. So if you generate a new controller by scaffolding in Rails 5 instead of getting a functional controller test, you will get an integration test by default. So if I just do Rails generate user and user controller and pass some actions in Rails 5, I will get an integration controller test like this. Okay. And with this change, there was no need to have functional test lying around at all. So Rails 5 has also soft-depricated functional controller test. Now when I say soft-depricated, that means is they are not completely removed but whatever you get by default in a newly generated Rails app is integration controller test. Now you will have a lot of old functional style test in your test app. And if you are upgrading to Rails 5, you don't have to worry because those tests will continue to work as it is. So it is not completely removed from Rails. They will still continue to work. But whenever you generate a new resource, you will get integration style tests. And the old test which were generated from this action controller test case, that code base is present in 5.0 release. But it might be extracted into 5.0. It might be extracted into a gem in future versions of Rails. But it will still be supported. So if you have thousands of controller tests, there is no need to go and change everything to integration test. Your old test will continue to work as it is with this gem. Now this change is not free. There are some implications of this change. Related to how we write our controller test. So this is an example from Rails 4. I am just trying to log in using sessions. So I am setting the user ID in the session directly in my setup block. This will change in Rails 4, Rails 5. I will have to test, I will have to change my code to actually make a request to my login URL. So earlier I was allowed to go and directly change the session values. But now that is no longer true. We have to make actual request to login. And then we will be able to make a request to our create action. Okay. So we have to remember this. Like now we cannot access sessions directly. We also cannot access request or responses directly without making a request. So first we will have to make a request. And then only we will be able to access the request object. So here in Rails 4 I was able to set the request address before making the like before making the index request and it is no longer allowed in Rails 5. So it will give me an error. And then I will have to pass the address manually when I make the request. So these are some of the things we need to remember while writing our controller test in Rails 5. Because they are now integration tests. So all the rules of integration tests now apply to our controller test. There are also some recommendations about what not to test in controller test in Rails 5 and specifically don't test controller internals. Now what is controller internals? So again a simple example. I'm just taking here that I have assigned repose and repose subs instance variables in my controller test. And I'm also verifying that I have rendered index template in my controller action. So and this is the equivalent code for this in my controller. I'm just and if I don't assign this at repose or at repose subs then my test will fail because it is expecting that that instance variable is assigned. But if you think of what we are actually testing in that test it is just scratching the surface. It is testing things on the surface. It is not actually testing what were the contents of those instance variables. We are just testing that okay that instance variable was assigned or not. We are just testing that index template got rendered or not. We are not testing what actually we were rendering inside that index template. And if we think of it actually testing what data were generated or actually testing what HTML content were generated by my controller action is better for like getting a confident test. So earlier we were just doing like we were just scratching the surface. We were not testing real things based on facts. So the same test can be written in Rails 5 as this using assert select. So what I'm doing here is I'm asserting that my HTML that was generated from this controller will have a CSS class repo item title and it will have a text inside that class issued as sandbox. And issued as sandbox is the actual database name for one of the my repos. So here I'm actually asserting facts. I'm verifying that I had this repo and that repo name got rendered in whatever response that got generated. I'm not just saying that okay add repos is there. That means the correct name got rendered. So this is the recommended way of testing things in Rails 5. And you can use this gem Rails DOM testing which gives us all the helpers related to assert select, CSS select. You can use block. So if you want to test something in particular deals you can write top level assert select and have nested assert select inside that. So check out this gem for more info about it. So this gives rise to another question. What we are actually doing? We are not actually testing our controller action in isolation that we are doing in Rails 4. That is no longer true. We are actually doing end to end testing. We are sending the request and we are testing the response or whatever the state changes that happen due to that response. So it gives rise to the end to end testing. We are no longer testing things in isolation at least when we are testing our controllers. In Rails 4 when we are doing when we are using Assign Assert template to test the controllers we are actually testing the controller view interface. Because controllers pass data to views in the form of instance variables when we say Assign's at repose we are just verifying that okay my controller is passing at repose to my view. We are not actually testing what exactly data that instance variable has. So we are testing the interface between controllers and views. But in Rails 5 the recommendation is that treat this interface just as a black box. There is no special thing about this interface that you need to go inside it and start writing test about it. Just treat it as black box. Just treat that your data will be passed properly. There is no need to write assertions about it. Treat the controller view interface just as an implementation detail. So that's the recommendation of writing test in Rails 5. And because of that Assert template and Assign's both things are deprecated in the Rails 5. So if you have your older tests which are using these helpers you will get a nice deprecation warning saying that you should not use them anymore. Okay. But there is always a part. So these helpers are also sometimes needed. Specifically let's say you have a engine, a Rails engine, and you have a separate Rails application. And your controller is coming from your engine. And your views are present in your application. Then your engine has a implicit contract with your view that this controller will have these many instance variables because your view depends on those instance variables for rendering. So in such cases testing controller actions isolated from their views is actually required. Take an example of device gen. So device has its own controllers for registration or pass words and other things. And there are no views. Views are actually present in our application. So in that case we know that okay device is going to set some instance variables in their controllers which we can use in our code. And in such cases actually testing controller actions isolated from your views is required. So it is discouraged but it is sometimes required. So the solution to this problem is there is a gen. So this code of assigns and asset template helpers is extracted into a separate gem and if you want to keep using them you should not actually but if you still want to use keep using them you can include this gem and they will work as it is. So testing in Rails 5 is much better experience much smarter experience with the test runner. It is also faster because now integration tests are comparatively fast as functional controller tests. There are a lot of deprecations as we saw. Actually there are more deprecations which I did not discuss in this talk. But I think the biggest takeaway that we can take from this talk is we are moving towards end-to-end testing. We are doing more and more like integration style of tests. The helpers are at the basic level right now but maybe in future we can get something like CapEvara helpers integrated into Rails. I don't know. But I think if we talk more about it and discuss more about it we will get some more nice solutions built on top of what we have right now. Because when we talk about testing we always talk about tools. What do you use? RSpec or Minitas? Oh use RSpec. Then don't talk to me. I use Minitas. But actually we should talk about testing strategies we use. Because I think if we start talking about strategies then both the tools will benefit from it and everybody will be happy. So yeah there is much more than this. I did not cover a lot of things like active job-assing adapter, random test ordering. So if you want to know more about what is happening in Rails 5 we will already show you the link but I'm going to show you again. Check out our block series about Rails 5. So it has like small blog posts about new features that are coming in Rails 5. We have around I think 40 to 45 blog posts right now. Other than that if you want to know what happens in Rails in each week you can check out this newsletter this week in Rails. It was started by Godfrey but now there are a lot of co-editors which edit the newsletter every week. So if you want to know what exactly happened, what feature got added in this week or what things got removed from Rails score then all of that information is present in this newsletter. So please subscribe to this newsletter. And that's it. Sheshay, thank you. You can follow me on Twitter. So the question was about when we test directly generated HTML then we are coupling our controller to view. And the answer to this is now we were like we were always thinking like controller and view are two separate things. So controller gets a request, it prepares some data for the request, it maybe adds something in database and a view gets rendered. But what Rails team is trying to encourage is controller and view are the same thing. Consider view as maybe as a private function of your controller and treat everything like whatever that comes out from that controller is the actual response not what instance variables we assign or what template we are trying to render. The output of the controller action is what is coming out of that controller which is the generated response. So the question is if you have HTML like if you are supporting HTML request and JSON request also how you how you will handle that. So in that case there is an addition in Rails 5 related to setting your like the request helpers that we have get, post, patch, delete. They all understand now JSON request by default. So you can just pass as JSON and it will treat it as a JSON request. So the response that will come out of that request will be JSON like JSON data. So you can write assertions against that JSON data. So you can write one test for your HTML and one test for your JSON and you can have two different requests. One will be HTML request, one will be JSON request. Okay, thank you.