Meaning of a struct with embedded anonymous interface?

后端 未结 5 1662
感动是毒
感动是毒 2020-12-07 08:42

sort package:

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

...

type reverse struct {
    Interface
}
         


        
5条回答
  •  眼角桃花
    2020-12-07 08:57

    I find this feature very helpful when writing mocks in tests.

    Here is such an example:

    package main_test
    
    import (
        "fmt"
        "testing"
    )
    
    // Item represents the entity retrieved from the store
    // It's not relevant in this example
    type Item struct {
        First, Last string
    }
    
    // Store abstracts the DB store
    type Store interface {
        Create(string, string) (*Item, error)
        GetByID(string) (*Item, error)
        Update(*Item) error
        HealthCheck() error
        Close() error
    }
    
    // this is a mock implementing Store interface
    type storeMock struct {
        Store
        // healthy is false by default
        healthy bool
    }
    
    // HealthCheck is mocked function
    func (s *storeMock) HealthCheck() error {
        if !s.healthy {
            return fmt.Errorf("mock error")
        }
        return nil
    }
    
    // IsHealthy is the tested function
    func IsHealthy(s Store) bool {
        return s.HealthCheck() == nil
    }
    
    func TestIsHealthy(t *testing.T) {
        mock := &storeMock{}
        if IsHealthy(mock) {
            t.Errorf("IsHealthy should return false")
        }
    
        mock = &storeMock{healthy: true}
        if !IsHealthy(mock) {
            t.Errorf("IsHealthy should return true")
        }
    }
    

    By using:

    type storeMock struct {
        Store
        ...
    }
    

    One doesn't need to mock all Store methods. Only HealthCheck can be mocked, since only this method is used in the TestIsHealthy test.

    Below the result of the test command:

    $ go test -run '^TestIsHealthy$' ./main_test.go           
    ok      command-line-arguments  0.003s
    

    A real world example of this use case one can find when testing the AWS SDK.


    To make it even more obvious, here is the ugly alternative - the minimum one needs to implement to satisfy the Store interface:

    type storeMock struct {
        healthy bool
    }
    
    func (s *storeMock) Create(a, b string) (i *Item, err error) {
        return
    }
    func (s *storeMock) GetByID(a string) (i *Item, err error) {
        return
    }
    func (s *storeMock) Update(i *Item) (err error) {
        return
    }
    
    // HealthCheck is mocked function
    func (s *storeMock) HealthCheck() error {
        if !s.healthy {
            return fmt.Errorf("mock error")
        }
        return nil
    }
    
    func (s *storeMock) Close() (err error) {
        return
    }
    

提交回复
热议问题