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

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

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题