Search code examples
unit-testinggostructcomposite-literals

How to fix "missing type in composite literal" in test cases


I am trying to write test code for the function ReadField() but I am having difficulty defining the test cases.

It gives an error "missing type in composite literal". I believe its just some syntax error.

I have tried defining the struct outside the function body but it would still give the same error.

ReadField(string, string, bool) (bool, string)

func TestReadField(t *testing.T){

    testCases := []struct {
        Name    string
        Input   struct{ 
            FirstString     string 
            SecondString    string 
            SomeBool        bool
        }
        Expected struct{
            IsValid bool
            Message string
        }
    }{
        //This is where the error points to.

        //Valid 
        {"Test Case 1",

        //Missing type error 
        {"FirstString", "SecondString", true},

        //Missing type error 
        {true, "testMessage"},},

        //Same goes for the remaining

        {"Test Case 2", 
        {"FirstString", "SecondString", false},
        {true, "testMessage"},},

        {"Test Case 3", 
        {"FirstString", "SecondString", true},
        {false, "testMessage"},},
    }

    for _, testCase := range testCases{
        t.Run(testCase.Name, func(t *testing.T){
            isValid, message := ReadField(testCase.Input.FirstString, testCase.Input.SecondString, testCase.Input.SomeBool)
            if isValid != testCase.Expected.IsValid || message != testCase.Expected.Message {
                t.Errorf("Expected: %b, %b \n Got: %b, %b", testCase.Expected.IsValid, testCase.Expected.Message, isValid, message)
            } else {
                t.Logf("Expected: %b, %b \n Got: %b, %b", testCase.Expected.IsValid, testCase.Expected.Message, isValid, message)
            }
        })  
    }
}

Solution

  • As the error indicates, you need to include the type in your declaration. Since you're using anonymous types, that means you must repeat the type definition. This is, of course, super annoying:

        //Valid 
        {"Test Case 1",
    
        //Missing type error 
        struct{ 
            FirstString     string 
            SecondString    string 
            SomeBool        bool
        }{"FirstString", "SecondString", true},
    
       // etc ...
    

    So what you should do is either use named types:

    type testInput struct{ 
        FirstString     string 
        SecondString    string 
        SomeBool        bool
    }
    type expected struct{
        IsValid bool
        Message string
    }
    testCases := []struct {
        Name     string
        Input    testInput
        Expected expected
    }{
        //Valid 
        {"Test Case 1",
    
        //Missing type error 
        testInput{"FirstString", "SecondString", true},
    
        // etc ...
    

    Or (my preference), flatten your top-level struct, making everything far more readable:

    testCases := []struct {
        Name              string
        InputFirstString  string 
        InputSecondString string 
        InputSomeBool     bool
        IsValid           bool
        Message           string
    }{
        //Valid 
        {"Test Case 1",
        "FirstString",
        "SecondString",
        true,
     // etc...
    

    I also strongly encourage you to use field labels in your definition, to improve readability:

        //Valid 
        {
            Name:              "Test Case 1",
            InputFirstSTring:  "FirstString",
            InputSecondString: "SecondString",
            InputSomeBool:      true,
     // etc...