How to mock single function in Swift? - unit-testing

My question is simple, how to mock a function (not a method) in Swift.
i.e., a standalone function not inside of a class.
Thank you.
EDIT:
Let's say I have the following function:
func distance(c1: CLLocation, c2: CLLocation) {
...
}
And I want to test my class:
class MyClass {
func selectedLocation(location: CLLocation) {
let text = "\(distance(self.currentLocation, location)) meters"
self.view.showText(text)
}
}
How do I mock the distance function?

To mock the distance function, you would need to do something like this
func distance(c1: CLLocation, c2: CLLocation) -> CLLocationDistance {
// ...
}
class MyClass {
var calculateDistance = distance
func selectedLocation(location: CLLocation) {
let text = "\(calculateDistance(self.currentLocation, location)) meters"
self.view.showText(text)
}
}
And in your test code you would need to do this:
func testCalculateDistanceFromLocation() {
let thing = MyClass()
thing.calculateDistance = { c1, c2 in /* return mock distance here */ }
// assert correct text appeared in the view
}
This way you are providing a new implementation of the distance function when in a testing environment. As far as I know you cannot completely replace the body of a top level function dynamically such that you don't need the internal class property that stores that function value.
This is kind of cumbersome though to do this for all your functions, so I say to only do this when you feel you absolutely need to substitute this extra mocked dependency. If possible, I would encourage you to test your class as a wnole unit, if it has few or no other external dependencies and treat the distance function as an implementation detail.

Do not know if I understand this correct. Swift does support global functions.
[update: This is what I do in the unit test]
public func getNumber()->Int //add public for unit testing
{
return 1
}
class MyClass: NSObject
{
func calculate()
{
let num = getNumber()
println(num)
}
}
///unit test case
import MyModule
extension NSObject
{
public fund getNumber()->Int
{
return 5 //mock implementation
}
}
func testExample() {
let myInstance = MyClass()
myInstance.calculate()
}

Related

Get private method with reflection in order to pass it to a higher order function in Kotlin

I'm having a hard time trying to get a private method in Kotlin using reflection in order to pass it as a parameter to a higher order function, here is what I got and what I need to do:
The function that gets the private method, probably what I should change or fix:
inline fun <reified T> T.getPrivateFunc(name: String): KFunction<*> {
return T::class.declaredMemberFunctions.first {
it.name == name
}.apply {
isAccessible = true
}
}
This is the high order function I have:
class MyService {
fun myHigherOrderFunction(action: () -> Unit) { /*...*/ }
}
These are the class and the private method I need to get somehow:
class SystemUnderTest {
fun privateFunc() { /*...*/ }
}
Finally a unit test where I I'm trying to make sure the proper method is passed to the high order function, I omitted details for simplification:
// ...
val serviceMock = MyService()
val sut = SystemUnderTest()
// Here is what I'm trying to accomplish
val privateMethod = sut.getPrivateMethod("privateFunc")
service.myHighOrderFunction(privateMethod)
// In the above line I get a compilation error: required () - Unit, found KFunction<*>
service.myHigherOrderFunction(privateMethod as () -> Unit)
// In the above line I get the following runtime error:
// ClassCastException: kotlin.reflect.jvm.internal.KFunctionImpl cannot be cast to kotlin.jvm.functions.Function1
I know the test can be done having the privateFunc as public and maybe annotating it with #VisibleForTesting, but what I want is to avoid compromising the design as long as I can.
Any ideas? Thanks in advance!
I don't think KFunction and KCallable have any notion of a bound receiver, so they are not invokable (have no operator fun invoke), and therefore don't qualify as functions. So I think you have to wrap the KFunction object in a function to be able to pass it to your higher order function. To call a KFunction, you pass the instance of the receiver class as the first argument.
val serviceMock = MyService()
val sut = SystemUnderTest()
val privateMethod = sut.getPrivateMethod("privateFunc")
service.myHighOrderFunction { privateMethod.call(sut) }
Edit: To internalize the creation of the wrapped function, you could do this:
inline fun <reified T> T.getZeroArgPrivateMethod(name: String): () -> Unit = {
T::class.declaredMemberFunctions.first {
it.name == name
}.apply {
isAccessible = true
}.call(this)
}
//...
val serviceMock = MyService()
val sut = SystemUnderTest()
val privateMethod = sut.getZeroArgPrivateMethod("privateFunc")
service.myHighOrderFunction(privateMethod)

How to test observer?

I would test presenter like this:
class MostPopularPresenter #Inject constructor(val mostPopularUseCase: MostPopularUseCase)
: Presenter<MostPopularView>() {
fun requestMostPopular(page: Int, update: Boolean) {
if (page <= 6)
mostPopularUseCase.execute(MostPopularObserver(), MostPopularUseCase.Params.createQuery(page, 15, update))
}
inner class MostPopularObserver : DisposableSingleObserver<MostPopularModel>() {
override fun onSuccess(t: MostPopularModel) {
this#MostPopularPresenter.view?.populateRecyclerList(t)
}
override fun onError(e: Throwable) {
this#MostPopularPresenter.view?.showError()
}
}
}
I have problem how to mock observer and force it to throw error or return value on success. I'm using mockito/junit. Can someone point me how to achieve it? Maybe my code is untestable?
An observer is an object that shouldn't be really tested. It has been already tested when it has been developed by a third developer, although there are some people that say, with a part of reason, that you should also test a third party library in order to ensure that it doesn't break your code between versions.
So, if you don't test the observer... how do you test your code? Simply, what you really need to test is the presenter itself. The code running inside the observer is part of the presenter. So instead of mocking the observer mock the useCase:
test useCaseFails() {
val usecase = // mock use case
when(usecase.execute(...))
.thenAnswer(/* receive the observer as first parameter
and make it emit an error */)
val presenter = ...
presenter.requestMostPopular(...)
// assert that presenter.view?.showError has been called
}
Another way of doing this (at least this is the way I usually code) is to make the useCase return an observable and subscribe it in the presenter:
class MostPopularPresenter #Inject constructor(val mostPopularUseCase: MostPopularUseCase)
: Presenter<MostPopularView>() {
private var lateinit observer : Disposable
fun requestMostPopular(page: Int, update: Boolean) {
if (page <= 6)
disposable = mostPopularUseCase.execute(MostPopularUseCase.Params.createQuery(page, 15, update))
.subscribe(t -> view?.populateRecyclerList(t),
e -> view?.showError())
}
}
This way you can easily mock your useCase so it returns a Subject you can control:
test useCaseFails() {
val usecase = // mock use case
val subject = PublishSubject()
when(usecase.execute(...))
.thenReturn(subject)
val presenter = ...
presenter.requestMostPopular(...)
subject.emitError(...) // <- pseudocode
// assert that presenter.view?.showError has been called
}
Usually there are not many cases where it is absolutely not possible to test. As far as I see it, you have a few options:
Put the observer into the constructor with a default value (but this might have some downsides with your dependency injection)
Put the observer into the function with a default value. This would work, but you have to choose if your API should contain this
Use the observer as property. In the test you can override this one.
All this variants would work and are listed here:
// observer in constructor
class MostPopularPresenter #Inject constructor(val mostPopularUseCase: MostPopularUseCase, val observer: DisposableSingleObserver<MostPopularModel> = MostPopularObserver())
: Presenter<MostPopularView>() {
// observer as property
internal var observer: DisposableSingleObserver<MostPopularModel> = MostPopularObserver()
// observer in function
fun requestMostPopular(page: Int, update: Boolean, observer: DisposableSingleObserver<MostPopularModel> = MostPopularObserver()) {
if (page <= 6)
mostPopularUseCase.execute(observer, MostPopularUseCase.Params.createQuery(page, 15, update))
}
}
internal class MostPopularObserver : DisposableSingleObserver<MostPopularModel>() { ... }
It would be even nicer, if you us a DisposableSingleObserverFactory and create the observer when it's needed.
class MostPopularPresenter #Inject constructor(val mostPopularUseCase: MostPopularUseCase, val observerFactory: DisposableSingleObserverFactory<MostPopularModel> = MostPopularObserverFactorty())
: Presenter<MostPopularView>() {
internal var observerFactory: DisposableSingleObserverFactory<MostPopularModel> = MostPopularObserverFactory()
fun requestMostPopular(page: Int, update: Boolean, observerFactory: DisposableSingleObserverFactory<MostPopularModel> = MostPopularObserver()) {
if (page <= 6)
mostPopularUseCase.execute(observerFactory.create(), MostPopularUseCase.Params.createQuery(page, 15, update))
}
}
internal class MostPopularObserver : DisposableSingleObserver<MostPopularModel>() {

How to mock NSDate in Swift?

I have to test some date calculation but to do so I need to mock NSDate() in Swift. Whole app is written in Swift and I'd like to write test in it as well.
I've tried method swizzling but it doesn't work (or I'm doing something wrong which is more likely).
extension NSDate {
func dateStub() -> NSDate {
println("swizzzzzle")
return NSDate(timeIntervalSince1970: 1429886412) // 24/04/2015 14:40:12
}
}
test:
func testCase() {
let original = class_getInstanceMethod(NSDate.self.dynamicType, "init")
let swizzled = class_getInstanceMethod(NSDate.self.dynamicType, "dateStub")
method_exchangeImplementations(original, swizzled)
let date = NSDate()
// ...
}
but date is always current date.
Disclaimer -- I'm new to Swift testing so this may be a horribly hacky solution, but I've been struggling with this, too, so hopefully this will help someone out.
I found this explanation to be a huge help.
I had to create a buffer class between NSDate and my code:
class DateHandler {
func currentDate() -> NSDate! {
return NSDate()
}
}
then used the buffer class in any code that used NSDate(), providing the default DateHandler() as an optional argument.
class UsesADate {
func fiveSecsFromNow(dateHandler: DateHandler = DateHandler()) -> NSDate! {
return dateHandler.currentDate().dateByAddingTimeInterval(5)
}
}
Then in the test create a mock that inherits from the original DateHandler(), and "inject" that into the code to be tested:
class programModelTests: XCTestCase {
override func setUp() {
super.setUp()
class MockDateHandler:DateHandler {
var mockedDate:NSDate! = // whatever date you want to mock
override func currentDate() -> NSDate! {
return mockedDate
}
}
}
override func tearDown() {
super.tearDown()
}
func testAddFiveSeconds() {
let mockDateHandler = MockDateHandler()
let newUsesADate = UsesADate()
let resultToTest = usesADate.fiveSecondsFromNow(dateHandler: mockDateHandler)
XCTAssertEqual(resultToTest, etc...)
}
}
If you want to swizzle it you need to swizzle a class that is internally used by NSDate and it is __NSPlaceholderDate. Use this only for testing since it is a private API.
func timeTravel(to date: NSDate, block: () -> Void) {
let customDateBlock: #convention(block) (AnyObject) -> NSDate = { _ in date }
let implementation = imp_implementationWithBlock(unsafeBitCast(customDateBlock, AnyObject.self))
let method = class_getInstanceMethod(NSClassFromString("__NSPlaceholderDate"), #selector(NSObject.init))
let oldImplementation = method_getImplementation(method)
method_setImplementation(method, implementation)
block()
method_setImplementation(method, oldImplementation)
}
And later you can use like this:
let date = NSDate(timeIntervalSince1970: 946684800) // 2000-01-01
timeTravel(to: date) {
print(NSDate()) // 2000-01-01
}
As others suggested I would rather recommend introducing a class Clock or similar that you can pass around and get a date from it and you can easily replace it with an alternative implementation in your tests.
Rather than use swizzling you should really design your system to support testing. If you do a lot of data processing then you should inject the appropriate date into the functions which use it. In this way your test injects the dates into these functions to test them and you have other tests which verify that the correct dates will be injected (when you stub the methods that use the dates) for various other situations.
Specifically for your swizzling problem, IIRC NSDate is a class cluster so the method you're replacing is unlikely to be called as a different class will be 'silently' created and returned.

Golang: Replace function unit testing

I'm working with Golang, and currently I'm doing some fun unit test with Testify, my file look like this
type myStruct struct {
field_1 string
}
func (self *myStruct) writeFirst() {
//doing something
//modify field_1
self.writeSecond()
}
func (self *myStruct) writeSecond() {
//doing something
}
In this case I'm testing writeFirst() but I'm trying to replace writeSecond() because it is using http stuff that I don't want to use because it access to internet.
I think that use a second struct and set myStruct as anonymous field will be the solution, but it's not working because me second struct and myStruct have a diferent context.
In this case I can't use mocks cause writeSecond is a method of the struct.
My test case looks like this:
func TestWriteFirst(t *testing.T) {
myStc := myStruct{}
assert.Equal(t,"My response", myStc.field_1)
}
All that I want is testing writeFirst without pass to writeSecond()
To illustrate the kind of refactoring mentioned by Not-a-Golfer in the comments, you could consider calling your second function only on an instance that is an interface:
type F2er interface {
Func2()
}
type S struct{ _f2 F2er }
var s = &S{}
func (s *S) f2() F2er {
if s._f2 == nil {
return s
}
return s._f2
}
func (s *S) Func1() {
fmt.Println("s.Func1")
s.f2().Func2()
}
Here: Func1 calls Func2 on s.f2(), not directly s.
If nothing has been set in s, s.f2() returns... itself: s
if s._f2 was replaced by any other struct which implements Func2, s.f2() returns that instance instead of itself.
See a complete example in this playground script.
Output:
TestFunc1
s.Func1
s.Func2
TestFunc1bis
s.Func1
testS.Func2 <=== different Func2 call

How do you test an extension method on an Interface which calls another method in that Interface with a mock created by Rhino Mocks?

I'm testing an extension method on an interface 'ISomeInterface'. The extension method actually calls to another method in the interface.
How do I set up a mock and the appropriate expectations (i want to set the expectation that 'SomeMethod', which is an defined method in the interface with a different signature then this extension method, will be called with 'someDifferentParam')
// Extension Method
public static ISomeInterface SomeMethod(this ISomeInterface someInterface, string someParam)
{
// do work, then call the defined method in the interface
someInterface.SomeMethod(int someDifferentParam)
return someInterface;
}
// tried to do the following but it errors
[Test]
public void SomeMethod_WithSomeInterface_CallsOtherSomeMethod()
{
const string someParam = "something";
const int someOtherParam = 1;
var mock = MockRepository.GenerateMock<ISomeInterface>();
mock.SomeMethod(someParam);
mock.AssertWasCalled(x => x.SomeMethod(someOtherParam));
}
EDIT
I finally got it working, but I'm open to suggestions/criticism. I'm just learning the ins/outs of Rhino Mocks myself =)
here is the real thing that I was testing. Since you can't compare two NHibernate.Criterion.Order objects by doing an Is.Equal or Is.SameAs I had to capture the arguments passed to the method call and then Assert on the ToString of the Order object because there are no public properties exposed on it.
// Extension Method
public static class NHibernateExtensions
{
public static ICriteria AddOrder(this ICriteria criteria, params OrderBy[] orderBys)
{
foreach (var b in orderBys)
{
var arr = b.Property.Split(',');
for (var i = 0; i < arr.Length; i++)
{
criteria.AddOrder(b.Direction == OrderDirection.Ascending
? Order.Asc(arr[i])
: Order.Desc(arr[i]));
}
}
return criteria;
}
}
// here is the test that works
[TestFixture]
public class NHibernateExtensionsTester : TestBase
{
[Test]
public void AddOrder_1OrderBy_CallsAddOrderOnICriteriaWithCorrectOrder()
{
const string testProperty = "SomeProperty";
var expected = (Order.Asc(testProperty)).ToString();
var orderBys = new[]
{
new OrderBy
{
Direction = OrderDirection.Ascending,
Property = testProperty
}
};
var mockCriteria = M<ICriteria>();
mockCriteria.AddOrder(orderBys);
var orderArgument = (Order)((mockCriteria.GetArgumentsForCallsMadeOn(x => x.AddOrder(null)))[0][0]);
Assert.That(orderArgument.ToString(), Is.EqualTo(expected));
}
}
Jon, since in effect you're just testing your extension method I see nothing wrong and this. I tried your code out and worked fine for me. Here is the exact code that I ran (using xunit.net and TD.Net). The test passed.
What error are you getting?