I am working on an App which uses UITableView and Animations extensively. It is becoming really difficult to write effect unit tests.
The view-controller concept in iOS is making the isolation of logic tough. This calls for lot of mocking/stubbing and I feel the Bacon framework(stripped down version of RSpec) for testing is not well advanced for this.
Basically, I could not find any iOS apps which are test driven for reference.
I am really wondering how to separate view and controller logic and effectively test drive it.
Any suggestions?
Have a look to this article and this one. Maybe you can get some ideas from them.
Related
It seems that in Xcode there are two kinds of tests, UI-tests which test an app running in another process using Automation, and Unit tests, where small units of code are tested in isolation. I wonder if there's a middle ground somewhere...
For instance, if I run unit tests there's a full app launched in memory that I don't use, because I am instantiating the classes that I need for testing in my test case classes. (I only know it's there because I see it in the simulator window and because my test classes sometimes accidentally communicate with it using notification center.)
It would be nice though, if I could use this app for integration tests. They would be similar to UI-tests, but much faster, and I would be able to access the implementation. I could for instance do that in order to install mocks so I can simulate behaviour of remote endpoints and see what the effects of certain responses are from the view point of the user.
The question is: Is there a good (documented) way to start up an app with mocks in the XCTest context and find that middle ground between unit tests and UI-tests?
funny thing, the other day we were also having this kind of problem. I'm not sure if this info might help you.
So the short answer to your specific question is that there is no written documentation in the apple docs(AFAIK) that specifically states how to make mock classes inside your tests but it doesn't necessarily mean you cant make one. There are a lot of ways on which you can make a mock up scenario to work with your code
manual way : making protocols/interfaces to be implemented by a working class and a mock class, overriding specific methods of working classes to somehow mock results, swizzling and etc.
3rd party way : notables (OCMock, Mockito)
in the case of objective c, there's a lot of 'em 3rd parties out there but with swift there are a few out there that are still in development because of the support that swift has with its runtime library (swift is yet to fully expose its runtime library)
here's a helpful link : https://academy.realm.io/posts/tryswift-veronica-ray-real-world-mocking-swift/ (great article)
Cheers
Belonging to the world of web development, I am used to powerful testing techniques and tools like Chai, Sinon, Mocha, Jasmine, to name a few, as well as to wide support and community, well-written books with deep insights. There are all possible cases I can imagine that are covered with existing tools.
Now, learning iOS development with Swift, I wonder, how I can thoroughly test methods of my app using stubs and mocks, imitating connecting to web services asynchronously and get myself sure tests can be written in a clear manner, creating peace of mind for my aging body.
I find the community is not so wide in iOS development, especially, Swift, as a result of the language being not so long on the landscape.
Please share the best practices for testing that can help me to create solid predictably behaving apps.
When developing iOS apps you have two possible test types you can use, one for unit testing, and one for acceptance testing. Those are referred in Xcode respectively as "Test Target" and "UI Test Target".
Within the tests target you can test all your app code by importing its Swift module using #testable import MyAppName, and then writing unit tests using XCTest, the framework provided by Apple.
On top on the tools provided by Apple, the FOSS community has developed other great testing libraries. In particular Quick is an testing framework that provides a syntax similar to Mocha.
When it comes to the UI tests target there is an important thing to be said: you can only test your app behaviour via those. There is no way to access the application code, everything is done through proxies that simulate the user's interaction with the UI. That is, in my opinion, for a good reason. The kind of tests one should write via tools that only allow UI interaction should be acceptance/funcitonal tests, which should only verify the app's behaviour. Not having access to the code is a good way to avoid misusing this tool.
I wonder, how I can thoroughly test methods of my app using stubs and mocks, imitating connecting to web services asynchronously and get myself sure tests can be written in a clear manner, creating peace of mind for my aging body.
Going deeper:
using stubs and mocks
Because of Swift's nature doing real mocking is quite hard. It's better to use fakes and doubles. There is also a great deal of literature online on why using mocks and stubs is seldom a good idea, for example this, this, this, and this.
imitating connecting to web services asynchronously
After having said all that it is true that sometimes stubbing is useful, such in the case you highlight. A good library to do this is OHHTTPStubs.
get myself sure tests can be written in a clear manner
I believe there are enough tools today to support writing clear and effective tests with little effort. The rest is up to you, your team, and the way you architect your app. As it is for any other programming language after all :D
If I can put a shameless plug in here, at the start of the year I wrote a post covering the state of testing in the iOS plaform, a lot of new things have happened since then, but it could be a good starting point if you want to dig deeper.
While developing an app I came to a point when I realized that I want to test my view controllers (and other objects as well) "outside" of the app. I've found a good blog post on testing view controllers, however, sadly enough, I'm not familiar with any kind of software testing at all. So almost everything written there is a bit confusing.
I'm looking for a good place to start and here are my questions:
I suppose it would be more useful to read something general on testing. What would you recommend?
What about iOS specific info? Tutorials on OCUnit (which is now integrated in Xcode), OCMock (which was mentioned in that blog post), UIAutomation?
Will I be able to "run" a separate view controller like an independent app (to tap buttons, type in text fields, etc.) without explicitly making such app? What tool may I use for that purpose?
What is your personal approach to this?
I would greatly recommend this resource as it touches on most of the questions that you have:
http://jojitsoriano.wordpress.com/2011/06/03/references-on-unit-testing-ui-automation-for-ios-applications/
Hope that helps!
Is there a proper way yet to unit test views with the aspx view engine?
I've been playing with various ways that will let me get a parseable string as a result like :
view.RenderView(viewContext);
But I'm not having any luck so far.
Most of what I've read strays into integration test territory. Integration test overlap a fair bit but don't allow me to use dummy data to check the output, which is the main thing I'm trying to achieve by unit testing views.
Have you checked out Selenium? It is directed at Web UI testing and is discussed in Hunt and Thomas' Pragmatic Unit Testing in C# with NUnit. It uses NUnit although it does so in a way that is really more of a system test than a Unit test (simply because you have to bring up the web app and navigate to your page to test it). Sorry that I didn't go down this route in my earlier answer but I was in a bit of a rush yesterday morning!
There is also NUnitAsp but that project has been essentially abandoned. It works and was widely praised in its day but I'm loathe to recommend anything that is no longer under active development.
What I have done is to create objects to "drive" the user interface and placed them all into a "BusinessObjects" dll. The interface essentially pulls its results from these objects when it is time to create the interface. I then Unit test against the Business Objects using standard NUnit unit tests. I'm afraid that your question might be a bit more specific to the MVC framework but I hope that this gives you some food for thought.
My advice is to not bother. Stick to testing the model and the controller. Checking for specific HTML is only going to lead to a fragile test base, that will break the moment you make the slightest change to the layout.
I have a Rails project which I neglected to build tests for (for shame!) and the code base has gotten pretty large. A friend of mine said that RSpec was a pain to use unless you use it from the beginning. Is this true? What would make him say that?
So, considering the available tests suites and the fact that the code base is already there, what would be my best course of action for getting this thing testable? Is it really that much different than doing it from the beginning?
This question came up recently on the RSpec mailing list, and the advice we generally gave was:
Don't bother trying to retro-fit specs to existing, working, code unless you're going to change it - it's exhausting and, unless the code needs to be changed, rather pointless.
Start writing specs for any changes you make from now on. Bug fixes are an especially good opportunity for this.
Try to train yourself into the discipline that before you touch the code, first of all write a failing example (=spec) to drive out the change.
You may find that the design of code which wasn't driven out by code examples or unit tests makes it awkward to write tests or specs for. This is perhaps what your friend was alluding to. You will almost certainly need to learn a few key refactoring techniques to break up dependencies so that you can exercise each class in isolation from your specs. Michael Feathers' excellent book, Working Effectively With Legacy Code has some great material to help you learn this delicate skill.
I'd also encourage you to use the built-in spec:rcov rake task to generate code coverage stats. It's extremely rewarding to watch these numbers go up as you start to get your codebase under test.
Maybe start with the models? They should be testable in isolation, which ought to make them the lowest-hanging fruit.
Then pick a model and start writing tests that say what it does. As you go along, think about other ways to test the code - are there edge cases that maybe you're not sure about? Write the tests and see how the model behaves. As you develop the tests, you may see areas in the code that aren't as clean and de-duplicated (DRY) as they might be. Now you have tests, you can refactor the code, since you know that you're not affecting behaviour. Try not to start improving design until you have tests in place - that way lies madness.
Once you have the models pinned down, move up.
That's one way. Alternatives might be starting with views or controllers, but you may find it easier to start with end-to-end transaction tests andwork your way into smaller and smaller pieces as you go along.
The accepted answer is good advice - although not practical in some instances. I recently was faced with this problem on a few apps of mine because I NEEDED tests for existing code. There simply was no other way around it.
I started off doing all unit tests, then moved onto functionals.
Get in the habit of writing failing tests for any new code, or whenever you're going to change a part of the system. I've found this has helped me gain more knowledge of testing as I go.
Use rcov to measure your progress.
Good luck!
Writing tests for existing code may reveal bugs in your code. These tests will force you to look at the existing code so you can see what test you need to write in order to get it to pass and you may see some code that could possibly be written better, or is now useless.
Another tip is to write a test when you encounter a bug so it should never re-occur, this is called regressional testing.
Retrofitting specs is not inevitably a bad idea. You go from working code to working code with known properties which allows you to understand whether any future change breaks anything. At the moment if you need to make a change how can you know what it will affect?
What people mean when they say that it is hard to add tests/specs to exisitng code is that code which is hard to test is often highly coupled which makes it hard to write low-level isolated tests.
One idea would be to start with full-stack tests using something like the RSpec story runner. You can then work from the 'outside in' isolating what you can in low-level isolated tests and gradually untangle the harder code bit by bit.
You can start writing "characterization tests". With this,you might what to try out the pretentious gem here:
It is still a work in progress though.