Cuckoo icon indicating copy to clipboard operation
Cuckoo copied to clipboard

Mock classes from third-party libraries

Open ealymbaev opened this issue 5 years ago • 14 comments

I have a class that accepts an instance of third-party library class in initializer (injection). But Cuckoo framework does not allow mocking a class that is not in our project. This class is located in third-party pod.

Is there any solution for this?

ealymbaev avatar Oct 08 '18 04:10 ealymbaev

Did anyone find a solution to this issue?

a-shelyuk avatar Dec 27 '18 07:12 a-shelyuk

I could really use a functionality like this; But at the same time I am wondering if it should be done? Shouln't we interact with external components through a protocol or a manager? Just wondering although I would definitly use this if it was implemented.

SwiftRabbit avatar Jan 17 '19 19:01 SwiftRabbit

I could also use this, my project is broken into several pods, and I would like to mock a protocol from a dependency pod in my tests of the pod that consumes the dependency.

rio258k avatar May 10 '19 20:05 rio258k

I'm not sure how this would be implemented, I imagine that given a module name and the exact paths to files to be mocked, this could work. However, there's no way this is going to be added to the input paths in the run script, it would be way too messy.

I think this would call for some kind of a config file where you would define the modules and their paths for much better readability, comment capability, and most importantly flexibility.

What I'm getting at with the flexibility is that there have been some issues with name collisions and this might fix it as well.

The run script is getting more and more bloated and perhaps this would prevent further bloating.

MatyasKriz avatar May 10 '19 23:05 MatyasKriz

First of all, I love this project, it's saved my bacon.

This would be awesome for a project I'm working on involving an external Bluetooth library which I'd love to be able to mock effectively to handle states that are just impossible to set up in a canned way through the interface available in the lib itself and to test my interactions with this lib.

Definitely, this would be a killer feature and would make this a complete mocking solution.

modohash avatar Jun 17 '19 16:06 modohash

Hey, @modohash.

While you're waiting for true third-party library support, you can try the experimental ObjC branch experimental/objectiveC if the Bluetooth library is in ObjC.

MatyasKriz avatar Jun 19 '19 15:06 MatyasKriz

@MatyasKriz Thanks for the response, unfortunately, the lib is in swift but I do have other libs that I'm using that are in ObjC so if the opportunity arises I'll give the experimental branch a try.

modohash avatar Jun 20 '19 08:06 modohash

I solved this with this script. By adding this to your Generate Cuckoo Mocks build phase you can generate mocks for your pods.

function generate_mocks_for_pod() {
  # Define output file. 
  OUTPUT_FILE="${PROJECT_DIR}/${PROJECT_NAME}Tests/Mocks/$1_GeneratedMocks.swift"
  echo "$1 Generated Mocks File = ${OUTPUT_FILE}"

  INPUT_DIR="${PODS_ROOT}/$1/Sources"
  echo "$1 Mocks Input Directory = ${INPUT_DIR}"

  input_files=()
  for arg in "${@:2}"; do
      input_files+=("${INPUT_DIR}/$arg")
  done

  # Generate mock files, include as many input files as you'd like to create mocks for.
  "${PODS_ROOT}/Cuckoo/run" generate   --no-timestamp   --testable "$1"   --output "${OUTPUT_FILE}"   "${input_files[@]}"
}

# Call generate_mocks_for_pods for each pod. Passing in the Pod name and the paths to the files to generate mocks for.
# When you add a new Pod to this list, you will need to run the generation, then run a `pod install`.
generate_mocks_for_pod "ThirdPartyPod1" "SourceFileName.swift" "SourceFileName2.swift"
generate_mocks_for_pod "ThirdPartyPod2" "SourceFileName.swift" "SourceFileName2.swift"

AnthonyMillerSF avatar Oct 29 '19 21:10 AnthonyMillerSF

Thanks, @AnthonyMillerSF for giving back to the community in the form of the script you provided.

This is close to what I'd like to include into the base functionality of Cuckoo in the near future, as well as giving the user the ability to define everything in a config file instead of hacking it away in the Build Phase script.

Until the time comes, I'm sure your script will be sufficient. Are there any caveats that we might help solve for the time being?

MatyasKriz avatar Nov 05 '19 14:11 MatyasKriz

I could really use a functionality like this; But at the same time I am wondering if it should be done? Shouln't we interact with external components through a protocol or a manager? Just wondering although I would definitly use this if it was implemented.

Yes but you have to have concrete implementation of your abstraction, right?! In that implementation will right unit tests to see if your concrete implementation is actually working properly. So you have to mock third-party, anyway

mecoFarid avatar Dec 27 '22 15:12 mecoFarid

@MatyasKriz Does this "But Cuckoo framework does not allow mocking a class that is not in our project" mean even I inherit third-party class/protocol in my class (let's say A), I still can't mock A?

mecoFarid avatar Dec 27 '22 15:12 mecoFarid

@MatyasKriz Does this "But Cuckoo framework does not allow mocking a class that is not in our project" mean even I inherit third-party class/protocol in my class (let's say A), I still can't mock A?

Unless you point Cuckoo generator to A, there's no way that Cuckoo can know which properties to override. If it's an ObjC class, you can try using the OCMock support. 🙂

MatyasKriz avatar Dec 27 '22 15:12 MatyasKriz

Well, of course I would add A as input file, that is for sure.

Back to question: Both my class A and the class/protocol it inherits from third-party library are both Swift classes, and I wanna mock the method from third-party library.

Example:

Third-party library:

open class Calculator{
    func add(a: Int, b: Int) -> Int{
        return a + b
    }
}

My project:

class ScientificCalculator: Calculator{
}

Question: Can I mock add method if I show ScientificCalculator as input file to Cuckoo generator?

Note: add is not open in case this info is important.

mecoFarid avatar Dec 27 '22 17:12 mecoFarid

Are there any caveats that we might help solve for the time being?

@MatyasKriz My 2 cents.

I tried to do it with GRDB.swift library:

Problem 1: GRDB.swift does not have Source folder, source code is placed in GRDB folder under GRDV.swift pod. Basically the solution can not be generalized as proposed by @AnthonyMillerSF Problem 2: Mocks are not generated for final classes of third-party library

mecoFarid avatar Dec 28 '22 19:12 mecoFarid