
Getting Started with {shinytest2} Part 3 || Using shiny.testmode in {shinytest2} || RStudio
00:00 Introduction 00:15 Testing production apps Part 1 - Getting started: https://youtu.be/SS1Na3c8lhk Part 2 - Exporting values: https://youtu.be/7KLv6HdIxvU Manually testing Shiny applications is often laborious, inconsistent, and doesn’t scale well. Whether you are developing new features, fixing bug(s), or simply upgrading dependencies on a serious app where mistakes have real consequences, it is critical to know when regressions are introduced. shinytest2 provides a streamlined toolkit for unit testing Shiny applications and seamlessly integrates with the popular testthat framework for unit testing R code. shinytest2 uses chromote to render applications in a headless Chrome browser. chromote allows for a live preview, better debugging tools, and/or simply using modern JavaScript/CSS. By simply recording your actions as code and extending them to test the more particular aspects of your application, it will result in fewer bugs and more confidence in future Shiny application development. Read up on shinytest2 here: https://rstudio.github.io/shinytest2/ Learn more about Shiny here: https://shiny.rstudio.com/ Got questions? The RStudio Community site is a great place to get assistance: https://community.rstudio.com/ Content: Barret Schloerke (@schloerke) Motion design and editing: Jesse Mostipak (@kierisi) Theme song: Brad PKL by Blue Dot Sessions (https://app.sessions.blue/browse/track/113507)
image: thumbnail.jpg
Transcript#
This transcript was generated automatically and may contain errors.
So, this example has some serious effects for production-sized apps where you have authentication or things that testing should not be confirming. One of the difficulties when doing production-sized apps and you're running it through unit tests is interacting with outside sources. This can be authentication, this can be database requests. One of the things that we recommend you do is you listen to a flag or a global option of shiny.testmode. If shiny.testmode is true, I recommend having a different UI or server or reactive behavior given this flag.
You can have things like the authentication isn't even addressed. If I do a restricted database call, maybe instead I load a CSV of information. One, we're not testing the database, we're actually just testing the Shiny app, so we need to try to isolate our tests to what we can control. Using this flag, we can turn that behavior on or turn it off. I think it's just really great as to how you can override your app's default behavior.
I think it's just really great as to how you can override your app's default behavior.
Testing production apps with shiny.testmode
Let's look at the app that we've been doing in the past two videos where we ask our name and it'll tell us the first letter of our name. Then let's just add in a third field of penguins. To lighten the mood a little bit, we're going to say, how many penguins are going to be coming for dinner? Let's just add this into our app. We have it here. I'm just going to run it for demonstration purposes. I click greet. It says, hello, first letter of your name is B, and there are 333 penguins coming for dinner. This is fun, but if I keep hitting greet, if we look as to where this penguin count is coming from, it's coming from this authenticated database request or something that I'm going to have return random data. If I click greet again, that's 330, 324, 336. This is not deterministic at all.
This is therefore not useful for testing because if you keep running this test over and over, it will fail. There will be no way for it to be correct because the data changes underneath. Instead, we can listen to our flag. I'm going to just wrap this one part and say, if we'll get an option of shiny.testMode, and if we'll default this value to false, but if it's true, then I want to return a test database request. This is something that returns static data and will only retrieve what I want it to have. Otherwise, if I'm not in test mode, then let's just do the authenticated database request. This will be stored into penguin data, and then the penguin data will count the number of rows, and then hopefully we have a consistent count.
Now, if I just run my app in reload app, this is not in testing mode, so we should still see our original behavior. I see Barrett. We see greet. It's something like 333, 321, a different amount of each time when I click greet. Let's run this just kind of looking at our application here. If I run this with the app, and I call app$view so that I have it, it opens up in the Chromium-based browser, and I have what's your name. We call set input Barrett. We call app greet. We can see that it updated, and here it says, hello, Barrett. First letter name is B, and there are 68 penguins coming for dinner. It's a funny phrase, but it's 68. It's not 300, and so if I click greet again and again and again and again, 68 is now constant, and it's still going to stay there.
If I look at the values to see what we have, app$get values, I have output penguins. There are 38 penguins coming for dinner. I could actually update that so that we have another exported test value of the penguin count. If I update with the penguin count, say penguin count equals a reactive expression where I export that penguin count, save it, and then I have to, I'm going to stop this app here, and then I'm just going to restart those interactive tests where I run app, and I click greet, and let's view it. I don't need to necessarily open up the viewer at the beginning. It's usually useful when debugging errors, but it still says 68. App$get value of export equals penguin count is 68. Perfect.
Now we can make assertions on this value, and it'll be consistent every single time. This is just so useful for getting around those database calls that take five, 10 minutes to execute, or you're asking a different API about something that is outside the control of Shiny. We want these unit tests to be consistent and fast. That way you want to do them, and you want to do them often.
We want these unit tests to be consistent and fast. That way you want to do them, and you want to do them often.


