I have never used Unit Testing and I understand the uses of it but I don't really know when and how to use it.
I would like to know when it's worth it to use Unit Testing, maybe with some examples.
The other answers tell when but not really how, so let me add an answer also.
When
Any time you are writing production code that you are going to keep, you should have Unit Testing for it. The most helpful training that I saw on this was the following 2-part video series:
Understanding Test Driven Development (part 1)
Unit Testing Best Practices with Roy Osherove (part 2)
The first five minutes or so are just intro so you can skip to the end of that.
How
I am using Xcode 7 with Swift.
Start a new project and add a Unit Test.
I am calling mine MyProject. If you open the MyProjectTests group in the Project Navigator, you will see that Xcode has already created a Unit Test file for you called MyProjectTest.swift.
You can delete all the example methods for now and add a new func to test your own class method. Be sure to add the line #testable import MyProject at the top. If your project name has spaces in it then replace the spaces with underscores. (For example, "My Example Project" would use #testable import My_Example_Project.)
I am following the naming pattern of testMethodNameBeingTested_Senario_ExpectedBehavior. Unit Test names must begin with "test".
I will do something like this:
import XCTest
#testable import MyProject
class MyProjectTests: XCTestCase {
func testSum_TwoNumbers_ReturnsSum() {
// Arrange (set up the needed objects)
let myClass = MyClass()
// Act (run the method you want to test)
let sum = myClass.sum(1, 2)
// Assert (test that the behavior is as expected)
XCTAssertEqual(sum, 3)
}
}
Of course, the build fails because we haven't added the MyClass class yet.
Add your class.
I am adding a Swift file to MyProject called MyClass.
class MyClass {
func sum(a: Int, _ b: Int) -> Int {
return a + b
}
}
Press the test button next to the Test Unit Class or method to run the test again and it should pass.
To see it fail (an important part of Unit Testing) you could do something like return 0 in the sum method of MyClass. Then you would see the following when you run test:
You can go back and fix this and then add more Unit Tests. You can also make other Unit Test files for different classes if you like. Just right click the MyProjectTest group in the Project Navigator and choose "New File" Then choose Test Case Class.
Related
Xcode UI Test example
You should almost always unit test and you should write code with unit tests in mind.
The extremists write tests even before writing the code (it's called TDD - Test Driven Development).
I'll give you a real life example: I recently had to code a sorted NSArray that supports "intervals". Meaning, the array should know how to insert an interval and keep it sorted.
For example, the array would look like this: [1-3, 5-9, 12-50]. In this example there are 3 intervals in the array, and as you can see they are sorted.
After I wrote my class (I called it IntervalsArray), I HAD to write tests to make sure that it works correctly and that I will not "break" it if I or someone else make changes to the code in the future.
Here are some example tests (pseudo-code):
Test 1:
- Create a new IntervalsArray
- Insert a new interval to the array
- (TEST) make sure the array has 1 object in it
Test 2:
- Create a new IntervalsArray
- Insert 2 intervals into the array: [1-3] and [5-9]
- (TEST) make sure there are 2 items in the array
- (TEST) make sure interval [1-3] comes before interval [5-9]
At the end I had something like 15 tests to cover every aspect of my new array.
Here's a good unit-testing with Xcode tutorial.
You can also write logic tests (which are more complicated than unit tests) to test your UI. Read a little about UIAutomation, which is Apple's way of testing UI. It's not perfect, but it's pretty good. Here's an excellent tutorial about this.
If you consider yourself a good programmer, you should write unit-tests for your code.
Write unit tests any time you write code that you'll have to maintain. That is, if you ever want to refactor anything — changing the code but keeping the behavior. Which is pretty much every bit of production code.
The counterexample of "Hello, World" is not to bother with code you plan to throw away. A "spike solution" is just to figure out how you might approach a problem. Once you've figured it out, throw it away and start again. Only this time, you start with tests.
Calling TDD "extremist" makes it sound irrational and impractical. In fact, once you learn TDD, it saves time/money.
See Unit Testing Example with OCUnit for an example of how TDD works.
Any time your writing an application that has classes, that are not your own. That is a good time to add unit tests, to test those classes.
All but the most basic apps will have their own classes, so its almost always a good idea to unit test.
If you are creating libraries that other programmers will use, or that you will use in multiple projects, those should always have unit tests.
Unit tests save you a lot of time when things change, for instance, a new version of the OS comes out, it is much better to test with the unit tests then to just test the app.
Related
I have an iOS app with some business logic. I would like to create an executable which would expose some calculations from the cli, so that I don't have to use the app.
Unfortunately, the code with the business logic that I want to expose depends on lots of other parts of the code, eventually pulling almost all the code. Even worse, it depends on some dependencies that are not available on macos (UIKit or DJISDK via pods).
I just want to write a main.swift, parse the arguments and use some functions from the codebase. What is the simplest way to do that ?
I don't mind if it's ugly (like pulling whole of UIKit in the executable) as long as it doesn't take to much time to implement.
I have two ideas:
remove all dependencies, optionally defining "dummy" classes compiled only for this target for some dependencies. That requires changing a lot of code, but seems to be cleaner.
find a way to pull the whole app in the new target. For example I have a UnitTests target which does that and can run on mac (though an app window appears when the tests run). But I have no idea how to do that.
Any help or guidance to good documentation would be greatly appreciated :)
I did my best to remove all unneeded dependencies, but there was a lot left that couldn't be removed easily. I resulted in using "dummy" classes to be able to compile without providing any logic.
Though it's not super elegant, it's a nice way to cut the dependency chain, and will let me remove the dependencies over time, while still being able to compile.
Ex:
// In common source file
class Business {
func usefulComputation() -> String {
...
}
func unneededFunction() -> UselessObject {
...
}
// In my CLI-target project
// file `DummyUselessObject.swift`
class UselessObject {
// add any function called from source file here, without putting any logic
}
// `main.swift`
let business = Business()
print(business.usefulComputation())
I’ve been struggling for hours trying to find a way to unit test my code. There’s no way to select the main target (MazeGeneratorTests is there b/c I already created it).
Here’s what the Project Navigator looks like (don’t mind the random structure):
After importing with #testable import MazeGenerator, calling anything from the module causes an Undefined symbols for architecture x86_64 error, e.g.:
func testPerformanceExample() throws {
measure {
let _ = generateNodes(rows: 20, cols: 20)
}
}
Edit: I’ve realized that the better way to achieve this is by using a static library (see Library vs. Framework. Here’s an example repo showing how to achieve this: Imericxu/example-testable-swift-cli.
I figured it out. The “Command Line Tool” target is kind of finicky, so you need to separate all your logic into a new Framework target—this comes with a unit test target—and make everything you want to be visible public. Then build and import the framework into your main.swift file.
This might be a special use case that I am dealing with here. Here is what my simple C# NUnit test that uses Moq looks like
Mock<ISomeRepository> mockR = new Mock<ISomeRepository>();
mockR.Setup(x => x.GetSomething).Returns(new Something(a=1,b=2);
--use the mocked repository here
Now later in this same unit test or another test case I want to invoke the real implementation of the method GetSomething() on this mockR object.
Is there a way to do that? My repository is Singleton at its heart. So even if I create a new object, the GetSomething method still returns the same Moq'd object.
That would largely depend on your implementation of that GetSomething, which is something you're not showing here ;). Also, I'm not sure that's even a valid setup, shouldn't there be a .Setup(..).Returns(..) there?
Mocks are used to represent dependencies of a class allowing that class to be tested without using their actual dependencies. Or you can do tests which involve the actual dependencies.
But using a mocked dependency and the real dependency within the same unit test sounds like you're not clear what your test is testing.
If it's another test case, it shouldn't be a problem either. Each test should not impact another, so if you set up the class under test separately that should be fine, even with a singleton.
I'm assuming that you're injecting the singleton dependency. If not, do that.
I have a bunch of fixture stuff that I want to do once for the test class but I also don't want the associated tests messing with it.
I don't really get the py.test fixture system yet so I'm not seeing how this is supposed to be done.
In vanilla Django this stuff is achieved with setUpTestData which lets you create some fixtures in the DB once for the test class. Then at the start of each test case it drops a transaction savepoint and at the end of each test it resets to that save point. (This is in addition to it transactioning around the entire class so as to leave a clean db at the end.)
I could get this functionality by inheriting off Django's TransactionTestCase but pytest-django seems to want to run without that and I've achieved everything else I need without doing so.
I've looked around for this quite a lot, and the best I could find is this pytest plugin, which I have not tested myself:
https://github.com/tipsi/pytest-tipsi-django
Per the pytest-django issue list, it looks like this has been raised before, but there is no movement towards a fix:
https://github.com/pytest-dev/pytest-django/issues/514
I am working on Unit Test using third party framework GHUnit, created project added GHUnit framework and other framework which are needed.
I created one class called TestCases, in that import library GHUnit and class which need to write test case.
I need to write test cases for 40 classes.
Do i need to write all test cases in one single class.
Do i need to create each class for testCase?
If Yes then when i try to create new class in separate testCase1,testCase2....testCase40 it can't able to show those testCases1 testCase2 ...testCase40
IT shows me a tableview and run button and only first testCases methods, its not showing me remaining testCases Class method.
Please advice in this situation. What action i need to do for this
#Advance thanks you all.,
Separate unit testing (functionality testing) integration testing (complete system working testing)
UNIT TESTING: (for each of those 40 classes)
Usually write different test class for each of the class, so that if there is a single change in any of the class can test it by specifically running that particular class, so if there is one or 40 or 100s of class better write unit test for each of them and ensure there functionality.
In each class better write different test cases for testing different functionality, so that it will be easy to identity (for a third person, not the one who develop it and written test case for that) where the error come from, and manage them.
Each function better test only one case, write different test cases for testing different functional behavior of each functions. So it may result with 100 test cases in a single class for testing a class with 10 functions. But it is good.
INTEGRATION TESTING: (for testing depended functionality of 40 classes)
When come to integration testing, write test cases for different behavior of complete system, in a single class with different possibilities (test cases).
And finally “Spend more time for testing than coding”.
Also ensure the coverage of test cases for the code is between 90% to 100%.