Issue #15 of objc.io is all about testing. It’s really good.
Pawel Dudek:
This is where behavior-driven development (BDD) comes it. It aims at solving these exact issues by helping developers determine what should be tested. Moreover, it provides a DSL that encourages developers to clarify their requirements, and it introduces an ubiquitous language that helps you to easily understand what the purpose of a test is.
Maybe I’m just not used to it, but I find it difficult to read BDD-style tests. There’s too much seemingly unnecessary DSL and the attendant block syntax.
Arne Schroppe and Daniel Eggert:
We structure our tests by using the Given-When-Then pattern—every test is split into three parts.
The given section sets up the environment for the test by creating model objects or bringing the system under test to a certain state. The when section contains the code we want to test. In most cases, this is only one method call. In the then section, we check the result of our action: Did we get the desired output? Was the object changed? This section consists mainly of assertions.
[…]
This makes using mocks even more convenient. We can specify that a mock should be verified right at the point where we create that mock[…]
[…]
[We] added a new dispatchGroup
property to all managed object contexts. We then exclusively used -performGroupedBlock:
in all our code.
With this, we could wait for all asynchronous work to be done inside our tearDown
method[…]
Jon Reid:
It may look odd to inject NSUserDefaults
, and that’s where this example may fall short. Remember, NSUserDefaults
is standing in for a dependency that creates trouble. It would make more sense for the injected value to be an abstraction (that is, an id
satisfying some protocol) instead of a concrete object. But I’m not going to discuss that in this article; let’s keep going with NSUserDefaults
for our examples.
[…]
We have five different forms of [dependency injection]. Each comes with its own set of pros and cons, so each has its place.
[…]
My advice for folks starting off with mock objects is to avoid using any mock object framework, at first, as you’ll have a better sense of what’s going on. My advice for folks starting off with DI is the same. But you can get even further in DI without a framework, relying solely on ‘Poor Man’s DI,’ where you do it yourself.
Luis Solano:
Private means private. Period. If you feel the need to test a private method, there is something conceptually wrong with that method. Usually it is doing too much to be a private method, which in turn violates the Single Responsibility Principle.
[…]
What To Do: Extract that private method to a separate class, give that class a properly defined contract, and test it separately. When testing code that relies on this new class, you can provide a test double of that class if needed.
Mike Lazer-Walker:
Naturally, it’s not like these are two rival schools of programmers; you’d be hard-pressed to see a mockist and a statist dueling it out on the street. This dichotomy is useful, though, in terms of recognizing that there are times when mocks are and are not the most appropriate tools in your tool belt. Different kinds of tests are useful for different tasks, and the most effective test suites will tend to have a blend of different testing styles. Thinking about what you are trying to accomplish with an individual test can help you figure out the best approach to take, and whether or not fake test objects might be the right tool for the job.
[…]
Many experienced testers warn that you “shouldn’t mock what you don’t own,” meaning that you should only create mocks or stubs of objects that are part of your codebase itself, rather than third-party dependencies or libraries. There are two main reasons for this, one practical and one more philosophical.
Klaas Pieter Annema:
Regardless of your method of testing, when testing user behavior, you want to stay as close to the user as possible. You want to make it appear to your code as if the user is interacting with it. Imagine the user is looking at a view controller, and then taps a button, which presents a new view controller. You’ll want your test to present the initial view controller, tap the button, and verify that the new view controller was presented.
By focusing on exercising your code as if the user had interacted with your app, you verify multiple things at once. Most importantly, you verify the expected behavior. As a side effect, you’re also simultaneously testing that controls are initialized and their actions set.
Orta Therox:
FBSnapShotTestCase
takes a UIView
or CALayer
subclass and renders it to a UIImage
. This snapshot is used to create tests that compare a saved snapshot of the view/layer and the version generated by your test. When it fails, it will create a reference image of the failed test, and another image to show the difference of the two.
Dependency Injection Objective-C Programming Testing
Dan Frommer:
Many Twitter users have noticed that Twitter is now inserting tweets into their timelines that seemingly don’t belong. This is not an accident. Twitter has updated its help document, “What’s a Twitter timeline?”
Scott Rosenberg:
The latest change is that the “favorite” — a tool most users rely on either to bookmark links they want to return to or to send a little head-nod of acknowledgment out to the tweet’s creator — is being put to use in a new way. Twitter is experimenting with showing you tweets from users you do not follow if those tweets are favorited by lots of other users (presumably, a lot of other users who you follow).
John Gruber:
So far, these changes are only evident when using Twitter’s first-party clients, but it’s a bad sign even if you use a third-party client like Tweetbot or Twitterrific. However, tweets that you favorite using a third-party client might start showing up in the timelines of your followers who do use Twitter’s own interfaces.
Update (2014-08-25): Jesper:
The reason I don’t like social media is that it takes two things that are polar opposites and duct tapes them together. Your own utility – to save links, to write text, to move files or materials, to keep notes, to communicate with yourself in the future, to communicate with some other specific people – and the social media outlet’s desire to fulfil its own objectives first.
[…]
When Twitter thinks it’ll improve everyone’s lives by inserting appropriate favorites, I don’t think they’re making that decision primarily for the filthy lucre. They’re doing it, in their minds, to make Twitter a better place to be in. The problem is that no one at Twitter seems to see that (or at least win any arguments about) nearly everyone else in this equation thinks it’s a worse result.
Update (2014-09-02): Brent Simmons:
What I do care about is that my blog isn’t part of a system where its usefulness is just a hook to get me to use it. It works the way I want to, and the company running the servers (DreamHost) doesn’t care one fig what I do.
[…]
The things that will last on the internet are not owned. Plain old websites, blogs, RSS, irc, email.
Twitter
Josh Anon:
Given the unfortunate news about Apple not actively developing Aperture anymore, I decided to try Lightroom while shooting in Svalbard. I’m trying to figure out if I should keep using Aperture for the immediate future and wait for Photos to be more fleshed out or to switch to Lightroom now and not have to migrate even more photos later (I have terabytes of digital photos from 12+ years of shooting digital cameras and scans of slides about 20 years ago managed in Aperture).
He has a good list of irks. I looked into switching to Lightroom but found it much harder to get used to than I expected. There are so many things about Aperture that seem to make more sense.
Adobe Lightroom Aperture Mac Mac App Photography
Alissa Walker (via John Gruber):
It was square, squat, and inherently cute. It was friendly. It was easy to use. I’m talking about the beige box with the blue grinning face that came to live with us in 1985. But I’m also talking about the font that came with it. It was the typeface Chicago that spelled out “Welcome to Macintosh,” ushering us into a new age of personal computing. But it was also a new age for digital type. Here was a typeface created explicitly for the Macintosh, part of designer Susan Kare’s strategy to customize everything from the characters to the icons — that happy computer, the wristwatch, an actual trashcan — to make it feel more human and less machine.
I liked Espy Sans better than Chicago’s replacement, Charcoal.
Font History Mac
Nick Hamann (via David Smith):
However, when haystack.len()
is less than 20, haystack.len() - 20
will be a very large number; we have an underflow error on our hands. This bug was causing the code to erroneously use the TwoWaySearcher
in general for haystacks of length less than 20, but in particular for the case of "bananas".contains("nana")
. The fix is to add 20
to the needle instead of subtracting it from the haystack […]
Bug Programming Rust Programming Language Underflow
Chris Eidhof:
I think it’s a really nice way of building APIs. The Github enum makes it very clear which endpoints are available, and the form of their parameters. By defining these things once, we can make it much harder for users of this API to make mistakes. For example, it’s not possible to pass in a nil
username, because the UserProfile
takes a non-optional string. If we wanted to add optional parameters, we have to be explicit about that.
The other nice thing is that all of the above code is independent of any networking library.
Open Source Programming Swift Programming Language Web API
Christoffer Lernö:
For normal closures there is no way to fix this problem. We can only have the closure return to it’s caller, which in this case is the function times we added to Int.
In many languages with macros, we would construct syntax by directly working with the syntax tree created by the compiler. This is can get fairly advanced and isn’t very easy to read.
As we see in this example we could do a lot of nice things if we just had something which “looks like a closure but unwinds the stack like an exception”
I would really like to see something like this in Swift.
Language Design Programming Swift Programming Language
Airspeed Velocity:
As we saw previously, if you pass a non-optional value to a function argument that expects an optional, it will get automatically converted into an optional by the compiler.
Ken Ferry points out something that goes one step further. If a function takes an argument of a function that returns an optional, and you pass into it a function that does not return an optional, the function will automatically be converted to return an optional.
Language Design Programming Swift Programming Language
Lukas Mathis:
As part of her Master’s degree at ETH Zürich, Laura Peer has developed an Android keyboard that solves this problem. The keyboard, called Kännsch, analyzes the text messages stored on the device it’s installed on. Together with a prebuilt database of words that different dialects have in common, this analysis allows the keyboard to accept Swiss German text without wrongly correcting words.
A keyboard extension would not be able to do this on iOS.
Android Extensions iOS Keyboard
Bruce Schneier:
This is why the oft-cited XKCD scheme for generating passwords -- string together individual words like ‘correcthorsebatterystaple’ -- is no longer good advice. The password crackers are on to this trick.
[…]
Last year, Ars Technica gave three experts a 16,000-entry encrypted password file, and asked them to break as many as possible. The winner got 90% of them, the loser 62% -- in a few hours. It’s the same sort of thing we saw in 2012, 2007, and earlier. If there’s any new news, it’s that this kind of thing is getting easier faster than people think.
Passwords Security
Some years ago, I added an SPF record to my domain. This makes it more likely that e-mails I send will get through to their recipients. The basic idea is that you declare (in your DNS record) which servers should be sending mail from your domain; any message not sent from one of those servers is probably spoofed. My SPF record for c-command.com looked something like this:
v=spf1 ip4:69.163.248.94 include:dreamhost.com include:fogcreek.com include:amazonses.com mx -all
The IP address was for my server. The SPF record also includes the SPF record for DreamHost, since I often send mail from their shared mail servers; Fog Creek, since I use FogBugz to send e-mails to customers; and Amazon SES, which I use to send order confirmation e-mails and serial number lookups. The mx means to look up the mail servers in my domain’s MX DNS record. The -all means that these are the only authorized servers.
It turns out that many mail servers don’t care if your SPF record is invalid. But some do, and I found this out when I was unable to send messages to a customer who had configured his server more strictly. When moving my site to a different server, I had updated the SPF record with the new IP address but accidentally included a space before it, which made the SPF record syntactically invalid.
I fixed this and, after waiting for the DNS to propagate, validated my SPF record. As expected, the syntax was now correct. However, the SPF record was still invalid:
Results - PermError SPF Permanent Error: Too many DNS lookups
I had not seen that before, but it turns out that RFC 7208 says:
Some mechanisms and modifiers (collectively, “terms”) cause DNS queries at the time of evaluation, and some do not. The following terms cause DNS queries: the “include”, “a”, “mx”, “ptr”, and “exists” mechanisms, and the “redirect” modifier. SPF implementations MUST limit the total number of those terms to 10 during SPF evaluation, to avoid unreasonable load on the DNS. If this limit is exceeded, the implementation MUST return “permerror”.
My SPF record looked like it only had four lookups:
$ host -t txt dreamhost.com | grep spf1
dreamhost.com descriptive text "v=spf1 ip4:62.229.62.0/24 ip4:69.64.144.0/20 ip4:98.124.192.0/18 ip4:66.33.206.0/24 ip4:66.33.195.34 ip4:208.113.189.254 ip4:208.113.200.0/24 ip4:66.33.216.0/24 ip4:208.97.187.128/25 ip4:64.90.62.0/24 ip4:64.90.63.0/25 ip4:64.90.63.128/26 include:_spf.goo" "gle.com include:sendgrid.net ~ALL"
$ host -t txt fogcreek.com | grep spf1
fogcreek.com descriptive text "v=spf1 ip4:64.34.80.172 ip4:69.90.190.164 include:_spf.google.com include:spf.mail.intercom.io include:amazonses.com -all"
$ host -t txt amazonses.com | grep spf1
amazonses.com descriptive text "v=spf1 ip4:199.255.192.0/22 ip4:199.127.232.0/22 ip4:54.240.0.0/18 -all"
$ host -t mx c-command.com
c-command.com mail is handled by 0 mx1.sub5.homie.mail.dreamhost.com.
c-command.com mail is handled by 0 mx2.sub5.homie.mail.dreamhost.com.
Unfortunately, the lookups within the dreamhost.com and fogcreek.com SPF records count, too. And those SPF records themselves have includes. The limit is quickly exceeded.
I was able to reduce the number of DNS lookups by removing include:dreamhost.com, because combination of my server’s IP address and the MX record were sufficient. DreamHost itself sends e-mails via Google and SendGrid, but it doesn’t do this on my behalf. Likewise, I could replace include:fogcreek.com with the IP addresses of the actual FogBugz mail servers, which are the only ones that FogCreek uses to send messages from my domain.
Now my SPF record looks like:
$ host -t txt c-command.com | grep spf1
c-command.com descriptive text "v=spf1 ip4:67.205.8.149 ip4:64.34.80.172 ip4:69.90.190.164 include:amazonses.com mx -all"
and it validates:
SPF record passed validation test with pySPF (Python SPF library)!
I will have to update it if any of the hard-coded IP addresses change, though.
Amazon SES Domain Name System (DNS) E-mail FogBugz Sender Policy Framework (SPF)
Knots 3D (App Store):
Tie, untie and rotate 93 knots with your finger in 3D! Knots 3D, our popular how-to knot app, will give you a whole new perspective on knots! Have you ever wondered what a knot looks like rotated 40° or maybe 90°? Or maybe you want to see what a Trilene knot or Constrictor knot looks like from the back? Use your finger to spin the knot and see how it looks from any angle in 3D!
Choose from 93 different knots and see how they’re tied in incredible detail. Watch the knot draw itself or use your finger to tie and untie the knot. Its easy to see where the virtual rope goes in and out and around. (Something about a rabbit and a hole and a tree right?) Zoom in on the knot to get a closer look or flip it around for another perspective.
Via Josh Centers and John Gordon.
iOS iOS App Knots 3D
John Gruber:
This recommendation is based not on aesthetics — how the controls look — but on the size of human fingertips. That’s the real constraint. 44 points isn’t a magic number; it’s a by-product of the size of the pixels on the original 2007 iPhone display (pre-retina, one point equaled one pixel). On every iPhone to date, from the original through the 5S and 5C, there has been a single consistent point resolution: 163 points per inch. That means a 44 × 44 point UI element has remained exactly the same physical size (as measured in inches or millimeters).
The original iPad introduced a second point resolution: 132 points per inch. This has remained consistent on the large (9.7 inch) iPads. The iPad Mini (both original and retina) uses the iPhone’s 163 points-per-inch resolution. Apple’s recommended target sizes did not change for the 9.7-inch iPad: they simply made the recommended tap targets physically larger. 44 points on an iPhone or iPad Mini is roughly 0.27 inches (6.9 mm). 44 points on a 9.7-inch iPad is 0.33 inches (8.4 mm). Everything is bigger by a factor of about 1.24.
Display iOS iPad iPhone Retina