agiledragon / gomonkey

gomonkey is a library to make monkey patching in unit tests easy
MIT License
1.93k stars 178 forks source link

remove "patch has been existed" check #91

Closed zhongyuanjia closed 1 year ago

zhongyuanjia commented 2 years ago

Take a look at the following code

type Repo struct {}

func (r *Repo) A() error { return errors.New("A") }

func (r *Repo) B() error { return errors.New("B") }

type Biz struct {
    repo *Repo
}

func (b *Biz) Do() error { 
    if err := b.repo.A(); err != nil { return err }
    return b.repo.B()
}

func Test() {
    patches := gomonkey.NewPatches()
    defer patches.Reset()

    biz := &Biz{repo: &Repo{}}
    // common patch
    patches.ApplyMethodReturn(biz.repo, "A", nil)             

        // test a scene
    patches.ApplyMethodReturn(biz.repo, "B", nil)
    err := biz.Do()
        So(err, ShouldBeNil)

        // test b scene
        // currently it will panic "patch has been existed"
        // what I need is to override the last patch
        patches.ApplyMethodReturn(biz.repo, "B", errors.New("error"))
        err = biz.Do()
        So(err, ShouldNotBeNil)
 }
agiledragon commented 2 years ago

Of course not! I suggest you to use a testing framework like goconvey, testify, and so on. Your test case is not single, it should be split into two. If you don't want to split the test case,you can use another API like ApplyMethodSeq.

zhongyuanjia commented 2 years ago

The following code is valid for version 2.2.0

patches := gomonkey.NewPatches()
defer patches.Reset()   
patches.ApplyMethod(val, "A", func() error { return nil })  
patches.ApplyMethod(val, "A", func() error { return errors.New("test") })   
val.A() // will return test error

When I upgrade to a new version, the above code reports a "patch has been exists" error

So I needed a way to bypass detection, This is the PR