# 3: Testing (Part 1), Dependency Injection ###### tags: `Tag(sp22)` ## Logistics and Comments * The in-class break timing poll is up on Ed! * Every now and then, a fellow student named **Nim Telson** will post questions on EdStem. For some reason, they always label their subject with `[Nim Telson]`. Nim is a bit of a troublemaker, so I've instructed the staff to not reply to such questions. However, all of **you** are allowed to help your fellow student out. You might learn something interesting along the way. (I **especially encourage** students who might feel rusty at OO or Java to think about these problems and reply with ideas -- and if you immediately know the answer, maybe prompt discussion, rather than giving it away.) * 0320 is very broad. It's not like a course on Deep Learning where you're learning, well, *deeply* about one narrow topic. This means the content delivery can't work the same way -- there's vital ideas that there's no lecture time to cover. Hence supplemental content: * labs; * readings and expanded lecture notes (think of notes as more than a lecture outline); * conceptual hours; * Ed posts (including by fellow students); * external online resources (more on this later!), etc. * How's Sprint 0 going? Reminder that 0320 is best taken with steady, consistent effort, **not** intense 1-to-2 day pushes. If you haven't yet started, start today. * Everyone should be set up now. If you're **not** at a point where the setup lab is behind you and you're able to use 0320's tools, your situation is precarious. Take immediate action. * Shopping period exists for a reason. If you have no OO design experience, **it's not too late to check out 0200**. ## Leftover from Tuesday: Dependency Injection What if I told **HALF** of you to design a thermostat? A physical device, with a little display and buttons and dials and so on. And the **HALF** were told to design the thermometer: the sensing component that reports ambient temperature. If you were on the thermostat team, would you wait for the thermometer to be designed and manufactured before you started work? (Hopefully not!) What would you do? One option would be to hook your sensing input up to a fake source of data, that you could control at will. Then, so long as you and the other team agreed on the **interface** for the data being reported, you could both work independently. This trick applies in software, too. Here's an example: ```java= interface TemperatureProvider { Temperature getCurrentTemperature(); } class Thermostat { // ... Thermostat(TemperatureProvider t) { this.provider = t } // ... } ``` The other team will build a `Thermometer` class implementing the `TemperatureProvider` interface. But you can also build your own fake data source, and start working immediately. This technique is called *dependency injection* in the OO literature, and it's a great trick to have in mind. It's great for easing the separation of work, and also incredibly useful for today's topic (testing). More on this idea next week. But I want to pull back and notice something. Especially at Universities, there can be a tension between "philosophies of programming", in particular the OO vs. functional perspectives. In 0320, we will shamelessly steal good ideas from both, and accept that everyone has some wisdom to offer. If you're a functional programmer, look for tools from the OO worldview; if you're primarily an OO programmer, pick up ideas from the functional perspective. Often, the same ideas appear under different names... <img src="https://i.imgur.com/4C45Wk2.jpg" alt="Dependency Injection ~= Currying" style="display:block; float:none; margin-left:auto; margin-right:auto; "> ## What We Talk About When We Talk About Testing We could easily spend the entire class on testing. We'll revisit the topic a couple more times throughout the semester. For now, **we're going to talk mostly about lower-level unit or system testing.** When we're talking about unit testing, there's usually 2 perspectives we can take: * transparent-box (also sometimes called "clear box" or white box") testing: **we have access to the code of the implementation under test**; and * opaque-box (also sometimes called "black box") testing: **we are writing tests based on a specification, and without recourse to the code under test**. **Question: Why do you think these perspectives have to be different?** <details> <summary>Think, then click!</summary> Here's one (of many) examples. If we've got access to the code under test, we can see which parts of that code our test suite exercises. If your tests exercise (say) 25% of the program statements in your code, do you think you've tested enough? This is the core idea of "code coverage" metrics. You can use libraries like [JaCoCo](https://www.jacoco.org) to examine how well your tests cover your implementation. (Note that even though the site is about an Eclipse plugin, the library itself doesn't require Eclipse.) Note that coverage percent is subtle. There's diminishing returns: it might be easy to get from 25% to 50%, and fairly easy to get to 70%, but 100% is very rare to see except on extremely high-risk or high-cost projects. On the other hand, thinking about tests in terms of the specification and the input and output types will give you a better understanding of the problem, and an opportunity to find strange corner cases that code-driven approaches won't always find. So, for the rest of today, we'll talk about testing without access to the code. </details> ### Clever Manka <a name="clever"></a> Your pre-class reading was Clever Manka, from a 1920's compilation called The Shoemaker's Apron, available on Project Gutenburg [here](https://www.gutenberg.org/files/33002/33002-h/33002-h.htm#Page_165). What in the world does a fairy tale have to do with testing? <B>If you're reading these notes without having been in lecture</B>: think about these questions first, before you read the answer! If you don't, you'll be robbing yourself of a chance to participate and learn. (These collapsible sections are meant to help you avoid spoilers while you think.) Don't worry about whether your answer is the same as mine. Especially in 0320, there are often many different good answers, even to technical questions. <details> <summary><B>Think, then click!</B></summary> Stories like Clever Manka appear in numerous places throughout the world. E.g., India has the story of [Hiranyakashipu](https://en.wikipedia.org/wiki/Hiranyakashipu), a king with a boon protecting him from death "by day or by night", "indoors and out", etc. Narasimha, an avatar of Vishnu, finds a way around the riddle. There is something special about boundary conditions. The Etruscans, and later the Romans, even had a deity devoted to them: [Janus](https://en.wikipedia.org/wiki/Janus), god of doorways. As testers, we should give boundaries the respect they deserve. Here's an example: "I have tested a positive number, and I have tested a negative number." Surely all numbers are positive or negative, right? (Is this true?) Here's another example: "I have tested this function on both true and false as inputs." (What's missing?) Never assume that the obvious partition of the space actually covers the space; be on the lookout for special cases, outliers, and even new dimensions about which to think. It's part of your job as a tester. (Are you aware of more mythological or literary settings for this sort of boundary-condition riddle? Share them with Tim!) </details> <br/> ## Representation vs. Domain Back in 2019, engineers at Apple had to deal with a major security bug in Facetime, the video-chat app that many iOS users use. It seems to have been reported earliest on [Twitter](https://twitter.com/MGT7500/status/1087171594756083713), but Apple didn't immediately (appear to) take the problem seriously. This isn't a class on PR or management, so we won't follow that line of discussion much further. The bug worked like this: suppose you wanted to spy on one of your Facetime contacts. You could start a video call with that contact, and then use "add a person" to invite your own number to the call. Now, even though your contact would see the invite, their microphone would be on, and sending you everything. It turns out that, depending on whether and how the contact dismissed the call, their video could end up on as well! Ouch. How did Apple miss this? We don't know, but we can speculate on the kinds of tests they didn't have in place. Suppose that you were responsible for testing "add a person" in an app like Facetime. Concretely, you might try to add any arbitrary phone number. What kinds of phone-number inputs should you test? <details> <summary><B>Think, then click!</B></summary> * toll-free numbers; * premium numbers (there are scams that trick people into dialing these); * the operator (0); * emergency services (are these always the same in every country?); * information and other special services; * reserved phone numbers; * in the U.S., same exchange vs. same area code vs. long-distance; * local numbers outside the U.S. standard format; * international connections; and even * **this device's number!** </details> <br/> Again, this list isn't anywhere near exhaustive. But do you notice something important here? <details> <summary><B>Think, then click!</B></summary> The inputs are numbers, and so if they happen to be represented internally as a number, you should also test the usual things you'd test for numbers (zero, something positive, MAXINT, ...). If they are represented as a String, perhaps there are similar things to test. But the added domain, that is, the fact that these are <i>phone</i> numbers, adds a lot more structure to the problem that you should exploit when writing tests. </details> <br/> Don't forget that your inputs have both an internal <i>representation</i> and a <i>domain-specific meaning</i>. Keep both in mind while you're testing. ## Let's take a break... (5-minute break...) ## Being Human Think of a country. What country are you thinking of? What if the question was in the context of software, like a statistical app that summarized United Nations data on population, GDP, and so on? <details> <summary><B>Think, then click!</B></summary> Chances are, the country you thought of was: - close to home; - large; or - in the news often. And it's even more likely that the country you thought of was **currently in existence**. You probably didn't say "the USSR" or "Austria-Hungary". And note that my choices there were all limited by my own historical knowledge. I went and [looked up more](https://en.wikipedia.org/wiki/List_of_former_sovereign_states) after writing that sentence. Even if we only count nations that existed after the U.N. was created, there are many: the Republic of Egypt (1953-1958), the Fourth Brazilian Republic (1946-1964), etc. </details> This is an example of something called _availability bias_ (or the _availability heuristic_). All humans exhibit it, and *often* it's an advantage: just like caching in a program, our brains tend to recall information in cache (except for us, it's an energy-saving measure). Tim isn't a cognitive scientist! If you want to learn more about this in depth, take a CLPS class. But even so, let's ask: **Why does availability bias impact software testing?** <details> <summary><B>Think, then click!</B></summary> You probably test what you have loaded into your mental cache. If you aren't thinking of it at the moment, or haven't been thinking of it recently, you likely won't test it. At least, not without very careful and disciplined thought. Even worse, if you aren't aware of the thing to begin with, you won't think to test it. Beware of the kind of thing that Iain Banks called an "outside context problem", translated from fiction into the real world of testing. </details> This pick-a-country question is another example of domain-aware testing, isn't it? (**Yes!**) ### Now let's have some fun! There are a lot of people in this class. Surely, many of you are knowledgeable about a domain that others aren't. Pick a domain you know about, and think about how inputs in related software might need to be tested with an awareness of that domain. What's your example domain? How would ideas in that domain be represented in your program (e.g., strings for phone numbers or country names -- but don't pick those examples)? What kind of domain-aware tests would you write? Work on this in small groups (or, if need be, solo) and share your thoughts in today's exercise form [here](https://forms.gle/cSRvT3qoARAUnF749).