•  


GitHub - rentziass/eventually: Keep retrying a bit of Go test code that you know _should_ pass, eventually, idiomatically.
Skip to content

Keep retrying a bit of Go test code that you know _should_ pass, eventually, idiomatically.

License

Notifications You must be signed in to change notification settings

rentziass/eventually

Folders and files

Name Name
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Eventually

PkgGoDev

Eventually provides support for running a test block that should eventually succeed, while still providing access to a testing.TB throughout the whole block. Eventually will keep trying re-running the test block until either a timeout or max attempts are reached. While this was created to test asynchronous systems I suppose it might help with flaky tests too :D. Here's an example:

func
 TestAsync
(
t
 *
testing.
T
) {
  
asyncProcessSucceeded
 :=
 false


  go
 func
() {
    
time
.
Sleep
(
100
 *
 time
.
Millisecond
)
    
asyncProcessSucceeded
 =
 true

  }()

  
eventually
.
Should
(
t
, 
func
(
t
 testing.
TB
) {
    
if
 !
asyncProcessSucceeded
 {
      
t
.
Fail
()
    }
  })
}

Notice how within the function you pass to eventually.Should you have access to a t testing.TB , this allows you to still use your helpers and assertions that rely on the good old t . Here's another example, using testify 's assert and require :

// code that sets up async consequences, e.g. writes some events on a queue


eventually
.
Should
(
t
, 
func
(
t
 testing.
TB
) {
  
events
, 
err
 :=
 readFromQueue
()
  
require
.
NoError
(
t
, 
err
)
  
require
.
Len
(
t
, 
events
, 
1
)
  
assert
.
Equal
(
t
, 
"event"
, 
events
[
0
])
})

Eventually has Should and Must functions, that correspond to Fail and FailNow respectively in case of failure.

Behaviour can be customised with use of Options , for example:

eventually
.
Should
(
t
, 
func
(
t
 testing.
TB
) {
  
// your test code here

},
  
eventually
.
WithTimeout
(
10
*
time
.
Second
),
  
eventually
.
WithInterval
(
100
*
time
.
Millisecond
),
  
eventually
.
WithMaxAttempts
(
10
),
)

And if you want to reuse your configuration you can do so by creating your very own Eventually . The example above would look something like:

eventually
 :=
 eventually
.
New
(
  
eventually
.
WithTimeout
(
10
*
time
.
Second
),
  
eventually
.
WithInterval
(
100
*
time
.
Millisecond
),
  
eventually
.
WithMaxAttempts
(
10
),
)

eventually
.
Should
(
t
, 
func
(
t
 testing.
TB
) {
  
// test code

})

eventually
.
Must
(
t
, 
func
(
t
 testing.
TB
) {
  
// test code

})

Why does this exist?

TL;DR: I like t a lot

Other testing libraries have solutions for this. Testify for instance has its own Eventually , but the function it takes returns a bool and has no access to an "inner" *testing.T to be used for helpers and assertions. Let's say for example that you have a helper function that reads a file and returns its content as a string, failing the test if it can't find the file (more convenient than handling all errors in the test itself). If the file you want to test is being created asynchronously using that helper within Eventually will halt the whole test instead of trying executing again. In Go code:

func
 TestAsyncFile
(
t
 *
testing.
T
) {
  
// setup


  assert
.
Eventually
(
t
, 
func
() 
bool
 {
    
contents
 :=
 readFile
(
t
, 
"path"
) 
// <-- this halts the whole TestAsyncFile, not just this Eventually run

    return
 contents
 ==
 "expected"

  })
}

func
 readFile
(
t
 *
testing.
T
, 
path
 string
) 
string
 {
  
f
, 
err
 :=
 os
.
Open
(
path
)
  
require
.
NoError
(
t
, 
err
)

  
// reading the file

}

Another available alternative is Gomega's Eventually (yes, this package has a very original name), which can be very convenient to use but requires buying into Gomega as a whole, which is quite the commitment (and I don't find a particularly idiomatic way of writing tests in Go but hey, opinions). This also still doesn't give access to a t with its own scope, you can do assertions within the Eventually block but if you have code that relies on *testing.T being around you cannot use it:

gomega
.
Eventually
(
func
(
g
 gomega.
Gomega
) {
  
contents
 :=
 readFile
(
t
, 
"path"
) 
// no t :(

  g
.
Expect
(
contents
).
To
(
gomega
.
Equal
(
"expected"
))
}).
Should
(
gomega
.
Succeed
())

About

Keep retrying a bit of Go test code that you know _should_ pass, eventually, idiomatically.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

- "漢字路" 한글한자자동변환 서비스는 교육부 고전문헌국역지원사업의 지원으로 구축되었습니다.
- "漢字路" 한글한자자동변환 서비스는 전통문화연구회 "울산대학교한국어처리연구실 옥철영(IT융합전공)교수팀"에서 개발한 한글한자자동변환기를 바탕하여 지속적으로 공동 연구 개발하고 있는 서비스입니다.
- 현재 고유명사(인명, 지명등)을 비롯한 여러 변환오류가 있으며 이를 해결하고자 많은 연구 개발을 진행하고자 하고 있습니다. 이를 인지하시고 다른 곳에서 인용시 한자 변환 결과를 한번 더 검토하시고 사용해 주시기 바랍니다.
- 변환오류 및 건의,문의사항은 juntong@juntong.or.kr로 메일로 보내주시면 감사하겠습니다. .
Copyright ⓒ 2020 By '전통문화연구회(傳統文化硏究會)' All Rights reserved.
 한국   대만   중국   일본