I am writing Objective-C unit tests in Xcode. I would like to extend my base class so I can reuse my setUp/tearDown methods. I created a header and put the imports there, since Xcode defaults to making just an implementation file.
Extending the base class works fine, except that all of its test methods are run a second time (or n times, depending on number of children).
My question is if this is the appropriate practice, or should I try something like base classes with no test methods?
Related
User guide contains following:
Usually, an extension is instantiated only once.
It's not very clear when extension can be instantiated many times? I'm supporting test suite with multiple extensions and every extension stores it's state in class fields. Everything works fine, but can I rely on this or should I refactor this code to use ExtensionContext.Store?
Usually, an extension is instantiated only once. So the question becomes relevant: How do you keep the state from one invocation of an extension to the next?
I think this sentence shall highlight that the same instance of an extension might be re-used for multiple tests. I doubt that the instance might be replaced in the middle of a test.
Multiple instances of an extension might be instantiated when a test uses programmatic extension registration (with #RegisterExtension). In such case, the test class creates its own instance of the extension. JUnit cannot reuse this instance in other test classes. But an instance created by declarative extension registration (with #ExtendWith) might be used for multiple test classes.
I am using OCMock to create some class mocks in an XCTest test suite. I also have a specific unit test where I mock nothing, in a separate test class/module. This test queries the runtime to look for a set of my classes with a specific prefix that conform to NSSecureCoding and perform several tests on them.
In the test, I obtain the list of classes using objc_getClassList. I am seeing a number of what looked to be mocked classes still hanging around, for example:
FooType-0x004fba20-3301757833
I can't seem to figure out why they are still hanging around because:
I called -stopMocking in the test -tearDown
I didn't stub any class methods, only instance methods
I have narrowed it down to the fact that the mocked objects were copied in the initializer of another non-mocked object in a separate test and test class/module.
Obviously, if you try to send a message to these classes or manipulate them, you crash with something akin to "NSInternalInconsistencyException", "No mock for class FooType-(address masked)-3301757833".
I was under the impression that the meta classes and mocks would be returned to normal when they were de-allocated or -stopMocking was called on them.
So I have a script test.py
from nose.tools import with_setup
class Test:
#with_setup(setup_func, teardown_func)
def test(self):
print "Hello World"
Can I have setup_func() and teardown_func() defined in an init.py in the same directory as "test.py".
Basically, the objective is to have a common setup and teardown for a bunch of test cases.
There is nothing magical about setup_func and teardown_func. You can certainly do that by importing them from any module, if it called init.py or __init__. I would suggest you put it in some other module, say test_setup.py because you may not want to have those definitions at the package level of the test module, and "explicit is better than implicit" philosophy will be enforced.
ADDED: However, you have a bigger problem here: with_setup is useful only for test functions, not for test methods or inside of subclasses. As written, in your code, your setup function will not be called regardless where it is specified, see here.
If you intend to make your tests as class methods, you would have to rely on setUp and tearDown methods of the unittest. If you wish, you can inherit your test class from a special setup class and reuse this same special class again for different tests.
How can you create the following structure:
CoreDataTests : XCTestCase
Entity1CoreDataTests : CoreDataTests
Entity2CoreDataTests : CoreDataTests
Explanation: I would like to write some tests related to core data (check), but I want to split them up into different test case classes, so in one test case class I would have tests related to the User entity, in another, the tests related to Comment entity. The catch here is that I'd like the two test case classes to share the setUp and tearDown methods implemented in CoreDataTests and just call them with super instead of having to copy-paste it around.
But since CoreDataTests is a test case class, it doesn't have a header file, so the EntityTest classes complain that they don't have a base class specified.
You can just create a subclass of XCTestCase as you would a normal class, with .h and .m files.
So just File Menu > New File > New Cocoa Class with XCTestCase as the super class.
You can then create new tests using that as the super class, however, you'll still need to import the superclass .h file as it's not added automatically.
I did this for exactly the same reasons, testing core data and having common methods to setup up the context.
One annoying thing though, it still shows up in the tests GUI, just with no tests.
I wonder if there is a way using OCMock can invoke a class method twice separately as if the app runs two times, but in fact, only once.
I want to test a class method. Due to some static variables inside the method, the method will keep its behavior all the time once it's called. Thus I can't test different behaviors at one time.
And of course, I can't add anything else to the class if the purpose is only for testing.
There is not a way to alter statically declared variables with OCMock without exposing them via Objective-C methods. You say "of course" you can't add anything to the class just for testing purpose, but this is not universally accepted. There is a an entire school of thought that believes your code itself should be designed to be tested.
- (NSInteger)someStatic
{
static NSInteger _someStatic = 42;
return _someStatic;
}
If you used a pattern like that that (for example, there may be better ones) you could mock your static. While this will add a method call anywhere the static is used, you may find it more important to have comprehensive testing.
OCMock version 2.1 has support for mocking class methods:
OCMock 2.1 released
15 March 2013
New release (2.1) which adds support for stubbing class methods and includes many contributed bug fixes. This release is compatible with Xcode 4.5/4.6.
The "Features" page on their website give some examples on how to mock a class method:
Class methods
[[[mock stub] andReturn:aValue] someClassMethod]
Tells the mock object that when someClassMethod is called on the class for which the mock object was created it should return aValue. This is the same syntax that is used to stub instance methods.
In cases where a class method should be stubbed but the class also has an instance method with the same name as the class method, the intent to mock the class method must be made explicit:
[[[[mock stub] classMethod] andReturn:aValue] aMethod]
The class can be returned to its original state, i.e. all stubs will be removed:
[mock stopMocking]
This is only necessary if the original state must be restored before the end of the test. The mock automatically calls stopMocking during its own deallocation.
Note: If the mock object that added a stubbed class method is not deallocated the stubbed method will persist across tests. If multiple mock objects manipulate the same class at the same time the behaviour is undefined.