douyu1990 2019-08-14 01:22
浏览 94
已采纳

从常量初始化变量并进行一些更改

I'm trying to create some scenarios for unit testing purposes and running into some problems when dealing with complex objects that I'd like to start from a base state.

In the below example is a simplified case where we have a query builder that may take three parameters. In this case we must always supply all three parameters to avoid a NPE when trying to access a reference.

package main

import (
  "fmt"
)

type Searcher struct {
  Param string
}

type CompleteSearcher struct {
  A *Searcher
  B *Searcher
  C *Searcher
}

func (c *CompleteSearcher) FormatQuery() string {
  return fmt.Sprintf("%s%s%s", c.A.Param, c.B.Param, c.C.Param)
}

func main() {
  testCases := []struct {
    scenario string
    want string
    searcher *CompleteSearcher
  }{
    {
      scenario: "A populated",
      want: "A",
      searcher: &CompleteSearcher{
          A: &Searcher{Param: "A"},
          B: &Searcher{},
          C: &Searcher{},
        },
    },
  }

  for _, tc := range testCases {
    got := tc.searcher.FormatQuery()
    if got != tc.want {
      fmt.Println("error")
    }
  }
}

My specific problem with this is mostly that the scenario must initialize all fields creating a noisy test where it's somewhat unclear what's actually under test. You can imagine with even more searchable fields, cache classes, backend classes, etc. that a simple enough function can have an enormous object responsible for actually doing the setup.

So what I'd like to do instead is something like the following.

baseSearcher := &CompleteSearcher{
  A: &Searcher{},
  B: &Searcher{},
  C: &Searcher{},
}
testCases := []struct {
  scenario string
  want string
  searcher *CompleteSearcher
}{
  {
    scenario: "A populated",
    want: "A",
    searcher: New(baseSearcher){A: &Searcher{Param: "A"}}
  },
}

Essentially I'd like to be able to test an entire object, but have the option to start with a "base" version of that object to prevent repeated setup in each scenario setup. From what I can tell there's no way to create a copy (even a shallow-copy) and then also do another assignment in a single statement, making it effectively impossible to have each scenario handle the object directly.

Any tips on how to resolve this issue?

  • 写回答

1条回答 默认 最新

  • douwang9650 2019-08-14 01:48
    关注

    If you are really wanting the one-liner, you could do something like

    func NewCS() *CompleteSearcher {
        return &CompleteSearcher{
            A:     &Searcher{},
            B:     &Searcher{},
            C:     &Searcher{},
            Cache: &Cacher{cache: make(map[string]interface{})},
        }
    }
    
    func (c *CompleteSearcher) WithA(s *Searcher) *CompleteSearcher {
        c.A = s
        return c
    }
    
    func (c *CompleteSearcher) WithB(s *Searcher) *CompleteSearcher {
        c.B = s
        return c
    }
    
    func (c *CompleteSearcher) WithC(s *Searcher) *CompleteSearcher {
        c.C = s
        return c
    }
    
    func (c *CompleteSearcher) WithCacher(s *Cacher) *CompleteSearcher {
        c.Cache = s
        return c
    }
    

    Playground example

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 如何通过代码传输视频到亚马逊平台
  • ¥15 php查询mysql数据库并显示至下拉列表中
  • ¥15 freertos下使用外部中断失效
  • ¥15 输入的char字符转为int类型,不是对应的ascall码,如何才能使之转换为对应ascall码?或者使输入的char字符可以正常与其他字符比较?
  • ¥15 devserver配置完 启动服务 无法访问static上的资源
  • ¥15 解决websocket跟c#客户端通信
  • ¥30 Python调用dll文件输出Nan重置dll状态
  • ¥15 浮动div的高度控制问题。
  • ¥66 换电脑后应用程序报错
  • ¥50 array数据同步问题