如何为json.Marshall的失败案例编写单元测试?

时间:2018-02-21 05:07:55

标签: json unit-testing go

我有以下代码:

func policyDocumentToStr(doc map[string]interface{}) (*string, error) {
   policy, err := json.Marshal(doc)
   if err != nil {
     log.Debugf("Error converting policy document to string. Error %s", err)
     return nil, err
   }

   policyAsString := string(policy)
   return &policyAsString, nil
}

我想写一个单元测试,它将涵盖json.Marshal(doc)返回错误的情况。任何人都可以建议我如何生成错误?什么样的输入功能会导致第policy, err := json.Marshal(doc)行出错?

3 个答案:

答案 0 :(得分:1)

为其提供无法用JSON表示的值。有很多方法可以做到这一点,包括使用自定义封送程序创建一个始终返回错误的类型。但最简单的方法之一是尝试编组一个频道:

x := map[string]interface{}{
    "foo": make(chan int),
}
_, err := json.Marshal(x)
fmt.Printf("Marshal error: %s\n", err)

Playground link

答案 1 :(得分:1)

定义实现json.Marshaler的类型。使用此类型可以产生任何所需的错误(包括json包中的错误值):

type FakeValue struct {
    err error
}

func (v FakeValue) MarshalJSON() ([]byte, error) {
    if v.err != nil {
            return nil, v.err
    }

    return []byte(`null`), v.err
}

func TestPolicyString(t *testing.T) {
    doc := map[string]interface{}{
            "fake_error": FakeValue{errors.New("fail!")},
    }

    _, err := policyDocumentToStr(doc)
    if err == nil {
            t.Fatal("Got nil, want error")
    }
}

答案 2 :(得分:0)

猴子修补是通过在运行时更改程序(通过替换函数或变量)来促进测试的一种方法。在这里,我们交换了json.Marshal,可以在测试时对其进行模拟。

var (
   jsonMarshal = json.Marshal
)

这是您的代码

func policyDocumentToStr(doc map[string]interface{}) (*string, error) {
  policy, err := jsonMarshal(doc)
  if err != nil {
    fmt.Printf("Error converting policy document to string. Error %s", err)
    return nil, err
  }

  policyAsString := string(policy)
  return &policyAsString, nil
}

测试代码看起来像这样

import (
    "testing"
    "errors"
)

func fakemarshal(v interface{}) ([]byte, error) {
    return []byte{}, errors.New("Marshalling failed")
}

func restoremarshal(replace func(v interface{}) ([]byte, error)) {
    jsonMarshal = replace
}

func TestPolicyDocumentToStr(t * testing.T){
    storedMarshal := jsonMarshal
    jsonMarshal = fakemarshal
    defer restoremarshal(storedMarshal)

    input := map[string]interface{} {
        "test": "test1",
    }
    tests := []struct {
        name string
        arg map[string]interface{}
        wantErr string
    }{
        {
            name: "Test if JSON Marshalling fails",
            arg: input,
            wantErr: "Marshalling failed",
        },
    }

    for _, tt := range tests {
        _, gotErr := policyDocumentToStr(tt.arg)
       if gotErr != nil && gotErr.Error() != tt.wantErr {
            t.Errorf("Expected %s but got %s", tt.wantErr, gotErr.Error())
       }
    }
}