gomuxgomock

Expected value is changed in Return Method of mockgen during its call


I am new to Go and recently, I am trying to write test cases using gomock package. I encountered a strange problem. I am trying to write test case for GetUsers whose implementation is

func (ctrl *HttpController) GetUsers(w http.ResponseWriter, r *http.Request) {

    users := ctrl.DS.GetUsers()
    
    // changed the name of the user
    users[0].Name = "User C"
    utility.JsonOkResponse(w, users)
} 

This is my test function

func TestGetUsers_Success(t *testing.T) {

    // setup mock interfaces
    ctrl, ds, _ := setup(t)

    // setup expected function calls
    expected := mock_data.Users
    ds.EXPECT().GetUsers().Return(expected)

    // create the request
    req := httptest.NewRequest("GET", "/users", nil)

    // generate router
    mux := mux.NewRouter()
    mux.HandleFunc("/users", ctrl.GetUsers)

    // create response recorder
    resp := httptest.NewRecorder()
    mux.ServeHTTP(resp, req)

    // check response contents
    assert.Equal(t, http.StatusOK, resp.Code)

    var users []model.User
    json.Unmarshal(resp.Body.Bytes(), &users)

    assert.Equal(t, expected, users)
}

These are the mock_data.Users

var Users = []model.User{user1, user2}

// sample user data
var user1 = model.User{
    ID:       1,
    Name:     "User A",
    Email:    "usera@gmail.com",
}

var user2 = model.User{
    ID:       2,
    Name:     "User B",
    Email:    "userb@gmail.com",
}

Now, I was expermenting with different scenarios for better understanding. So, in this case my test case should fail (although it still passes) because I changed one of the user's name in GetUsers function but strangely, the test case still passes and when I do assert.Equal(t, expected, users) the value in the expected is also changed with new user name User C. Is the expected value passed as pointer in Return method of mockgen or Am I missing something basic ?


Solution

  • This happens because when you do expected := mock_data.Users you are making a copy of the slice header, but not the underlying array, so changes to the array of the first slice will change the other. Please take a look at this article for more details.

    If you want to make a copy of the slice you need to use the builtin copy function, like so:

    expected := make([]model.User, len(mock_data.Users))
    copy(expected, mock_data.Users)