danger / swift

⚠️ Stop saying "you forgot to …" in code review
https://danger.systems/swift/
MIT License
1.05k stars 141 forks source link

DangerDSL mocking [IDEA] #533

Open Nikoloutsos opened 2 years ago

Nikoloutsos commented 2 years ago

Hi, first of all thanks for this danger-js wrapper it is so cool 🎉. I do have an idea that I'd like to hear your opinion about:

As I was developing a danger plugin I wanted to make it fully-testable. For doing that I had to mock DangerDSL which I spent a lot of time and the only way I found was initialising through JSON files. So if i have 200 tests I should have 200 JSONs (1000 lines each) . So i came up with this idea 👇

Proposal

We can make use of Runtime library https://github.com/wickwirew/Runtime that will allow us to change let properties of dangerDSL😆. At this point in my repo I have implemented this and working well.

/// Gives the ability  to a struct/class to modify properties even let through runtime mirroring
protocol RuntimeModifiable {
    /// Use this method to change a property on your RuntimeModifiable
    /// ```swift
    /// // In case you want to pass nil!
    /// try mutablePR.rchange(property: "assignee", with: Optional<GitHub.User>.none)
    /// ```
    mutating func rchange(property: String, with value: Any) throws
}

extension RuntimeModifiable {
    mutating func rchange(property: String, with value: Any) throws {
        let info = try typeInfo(of: type(of: self))
        let property = try info.property(named: property)
        try property.set(value: value, on: &self)
    }
}

// MARK: DangerDSL struct
extension GitHub.PullRequest: RuntimeModifiable {}
extension GitHub: RuntimeModifiable {}
extension DangerDSL: RuntimeModifiable {}
extension GitHub.User: RuntimeModifiable {}
...

and test now looks like this (in this test we make dangerDSL to have an assignee):

func testAssigneeExist() throws {
        // Given
        var fixture = githubWithFilesDSL()
        var mutableGithub = fixture.github!
        var mutablePR = fixture.github.pullRequest

        try mutablePR.rchange(property: "assignees", with: [GitHub.User(id: 0, login: "", userType: .user)])
        try mutableGithub.rchange(property: "pullRequest", with: mutablePR)
        try fixture.rchange(property: "github", with: mutableGithub)

        let sut = AssigneeExistsStep(danger: fixture)
        // When
        sut.execute()

        // Then
        XCTAssertTrue(sut.status.isSuccess)
    }

By doing this we can stub what we want in dangerDSL in contrast of bombarding the whole package with JSON files. Maybe this idea can be a seperate package (danger plugin) that can be used for easier DangerDSL mocking.

What do you think?

f-meloni commented 1 year ago

Hey @Nikoloutsos, thank you for putting this proposal together :) We already have something similar to allow you to modify the DangerDSL: Look for example this test file, where the created files are modified from the DSL in the test https://github.com/f-meloni/danger-swift-coverage/blob/master/Tests/DangerSwiftCoverageTests/CoverageTests.swift. This only allows you to modify the created/modified/deleted files, and allows you to create a fileMap to stub also the content of the file when you go to read it with danger.utils, so is a lot simpler than what you suggest, and would be cool to have something more complex :).

We have https://github.com/danger/swift/tree/master/Sources/DangerFixtures that is already a testing lib, and I would be happy to see something like the code you suggest, or something like a builder there, that can then help the creators of Danger plugins :)