How to assert equals on structs with a time field #1612
-
I have this struct type DBJob struct {
Id int64 `db:"id"`
Name string `db:"name"`
Data string `db:"data"`
State JobState `db:"state"`
CreatedAt time.Time `db:"created_at"`
AvailableAt time.Time `db:"available_at"`
} And my tests fail because of the CreatedAt and AvailableAt. Let's set an example: In a test if I insert into the DB an instance and recover it, there is a negligible loss of precision but since it's not the exact same time the test fails. In testify there is func TestTimes(t *testing.T) {
// container has a testcontainers postgres container and a *sqlx.DB instance
container := prepareForTestCase()
t.Cleanup(func() {
if err := container.Shutdown(); err != nil {
t.Errorf("Error shuting down test container: %v", err)
}
})
expected := jobs.DBJob{
Id: 1,
Name: "Test job",
Data: "{}",
State: jobs.JobStatePending,
AvailableAt: time.Now().UTC(),
CreatedAt: time.Now().UTC(),
}
if _, err := container.DB.NamedExec(
`INSERT INTO jobs(id, name, data, state, created_at, available_at)
VALUES (:id, :name, :data, :state, :created_at, :available_at);`,
expected); err != nil {
t.Errorf("Error inserting job %v: %v", expected, err)
}
var found jobs.DBJob
row := container.DB.QueryRowx(`SELECT * FROM jobs WHERE id = 1;`)
row.StructScan(&found)
assert.Equal(t, expected, found, "The jobs do not match") // <-- Fails
} This equals fails
The time is the same but the millisecconds which seems to be a loss of precition. How can I assert that two instances of this struct are equals whithing like 500ms? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
My recommendation for such structs, where you do not actually want some fields to be Equal is to write a test helper function to define what you consider to be "equal": func assertDBJobCloseEnough(t *testing.T, expected, actual jobs.DBJob) bool {
t.Helper()
return assert.Equalf(t, expected.Id, actual.Id, "Expected Id=%d but got Id=%d", expected.Id, actual.Id)
& assert.Equalf(t, expected.Name, actual.Name, "Expected Name=%s but got Name=%s", expected.Name, actual.Name)
& assert.Equalf(t, expected.Data, actual.Data, "Expected Data=%s but got Data=%s", expected.Data, actual.Data)
& assert.Equalf(t, expected.State, actual.State, "Expected State=%v but got State=%v", expected.State, actual.State)
& assert.WithinDurationf(t, expected.AvailableAt, actual.AvailableAt, time.Millisecond*500, "Expected AvailableAt=%v±0.5s but got AvailableAt=%v", expected.AvailableAt, actual.AvailableAt)
& assert.WithinDurationf(t, expected.CreatedAt, actual.CreatedAt, time.Millisecond*500, "Expected CreatedAt=%v±0.5s but got CreatedAt=%v", expected.CreatedAt, actual.CreatedAt)
} Another option is to fully constrain the test environment's inputs, including time, so that you can fully test for state. This might mean making an interface to time that you can mock, or designing your internal APIs differently. |
Beta Was this translation helpful? Give feedback.
My recommendation for such structs, where you do not actually want some fields to be Equal is to write a test helper function to define what you consider to be "equal":