1package suite 2 3import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12) 13 14// SuiteRequireTwice is intended to test the usage of suite.Require in two 15// different tests 16type SuiteRequireTwice struct{ Suite } 17 18// TestSuiteRequireTwice checks for regressions of issue #149 where 19// suite.requirements was not initialised in suite.SetT() 20// A regression would result on these tests panicking rather than failing. 21func TestSuiteRequireTwice(t *testing.T) { 22 ok := testing.RunTests( 23 allTestsFilter, 24 []testing.InternalTest{{ 25 Name: "TestSuiteRequireTwice", 26 F: func(t *testing.T) { 27 suite := new(SuiteRequireTwice) 28 Run(t, suite) 29 }, 30 }}, 31 ) 32 assert.Equal(t, false, ok) 33} 34 35func (s *SuiteRequireTwice) TestRequireOne() { 36 r := s.Require() 37 r.Equal(1, 2) 38} 39 40func (s *SuiteRequireTwice) TestRequireTwo() { 41 r := s.Require() 42 r.Equal(1, 2) 43} 44 45type panickingSuite struct { 46 Suite 47 panicInSetupSuite bool 48 panicInSetupTest bool 49 panicInBeforeTest bool 50 panicInTest bool 51 panicInAfterTest bool 52 panicInTearDownTest bool 53 panicInTearDownSuite bool 54} 55 56func (s *panickingSuite) SetupSuite() { 57 if s.panicInSetupSuite { 58 panic("oops in setup suite") 59 } 60} 61 62func (s *panickingSuite) SetupTest() { 63 if s.panicInSetupTest { 64 panic("oops in setup test") 65 } 66} 67 68func (s *panickingSuite) BeforeTest(_, _ string) { 69 if s.panicInBeforeTest { 70 panic("oops in before test") 71 } 72} 73 74func (s *panickingSuite) Test() { 75 if s.panicInTest { 76 panic("oops in test") 77 } 78} 79 80func (s *panickingSuite) AfterTest(_, _ string) { 81 if s.panicInAfterTest { 82 panic("oops in after test") 83 } 84} 85 86func (s *panickingSuite) TearDownTest() { 87 if s.panicInTearDownTest { 88 panic("oops in tear down test") 89 } 90} 91 92func (s *panickingSuite) TearDownSuite() { 93 if s.panicInTearDownSuite { 94 panic("oops in tear down suite") 95 } 96} 97 98func TestSuiteRecoverPanic(t *testing.T) { 99 ok := true 100 panickingTests := []testing.InternalTest{ 101 { 102 Name: "TestPanicInSetupSuite", 103 F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupSuite: true}) }, 104 }, 105 { 106 Name: "TestPanicInSetupTest", 107 F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupTest: true}) }, 108 }, 109 { 110 Name: "TestPanicInBeforeTest", 111 F: func(t *testing.T) { Run(t, &panickingSuite{panicInBeforeTest: true}) }, 112 }, 113 { 114 Name: "TestPanicInTest", 115 F: func(t *testing.T) { Run(t, &panickingSuite{panicInTest: true}) }, 116 }, 117 { 118 Name: "TestPanicInAfterTest", 119 F: func(t *testing.T) { Run(t, &panickingSuite{panicInAfterTest: true}) }, 120 }, 121 { 122 Name: "TestPanicInTearDownTest", 123 F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownTest: true}) }, 124 }, 125 { 126 Name: "TestPanicInTearDownSuite", 127 F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownSuite: true}) }, 128 }, 129 } 130 131 require.NotPanics(t, func() { 132 ok = testing.RunTests(allTestsFilter, panickingTests) 133 }) 134 135 assert.False(t, ok) 136} 137 138// This suite is intended to store values to make sure that only 139// testing-suite-related methods are run. It's also a fully 140// functional example of a testing suite, using setup/teardown methods 141// and a helper method that is ignored by testify. To make this look 142// more like a real world example, all tests in the suite perform some 143// type of assertion. 144type SuiteTester struct { 145 // Include our basic suite logic. 146 Suite 147 148 // Keep counts of how many times each method is run. 149 SetupSuiteRunCount int 150 TearDownSuiteRunCount int 151 SetupTestRunCount int 152 TearDownTestRunCount int 153 TestOneRunCount int 154 TestTwoRunCount int 155 TestSubtestRunCount int 156 NonTestMethodRunCount int 157 158 SuiteNameBefore []string 159 TestNameBefore []string 160 161 SuiteNameAfter []string 162 TestNameAfter []string 163 164 TimeBefore []time.Time 165 TimeAfter []time.Time 166} 167 168// The SetupSuite method will be run by testify once, at the very 169// start of the testing suite, before any tests are run. 170func (suite *SuiteTester) SetupSuite() { 171 suite.SetupSuiteRunCount++ 172} 173 174func (suite *SuiteTester) BeforeTest(suiteName, testName string) { 175 suite.SuiteNameBefore = append(suite.SuiteNameBefore, suiteName) 176 suite.TestNameBefore = append(suite.TestNameBefore, testName) 177 suite.TimeBefore = append(suite.TimeBefore, time.Now()) 178} 179 180func (suite *SuiteTester) AfterTest(suiteName, testName string) { 181 suite.SuiteNameAfter = append(suite.SuiteNameAfter, suiteName) 182 suite.TestNameAfter = append(suite.TestNameAfter, testName) 183 suite.TimeAfter = append(suite.TimeAfter, time.Now()) 184} 185 186// The TearDownSuite method will be run by testify once, at the very 187// end of the testing suite, after all tests have been run. 188func (suite *SuiteTester) TearDownSuite() { 189 suite.TearDownSuiteRunCount++ 190} 191 192// The SetupTest method will be run before every test in the suite. 193func (suite *SuiteTester) SetupTest() { 194 suite.SetupTestRunCount++ 195} 196 197// The TearDownTest method will be run after every test in the suite. 198func (suite *SuiteTester) TearDownTest() { 199 suite.TearDownTestRunCount++ 200} 201 202// Every method in a testing suite that begins with "Test" will be run 203// as a test. TestOne is an example of a test. For the purposes of 204// this example, we've included assertions in the tests, since most 205// tests will issue assertions. 206func (suite *SuiteTester) TestOne() { 207 beforeCount := suite.TestOneRunCount 208 suite.TestOneRunCount++ 209 assert.Equal(suite.T(), suite.TestOneRunCount, beforeCount+1) 210 suite.Equal(suite.TestOneRunCount, beforeCount+1) 211} 212 213// TestTwo is another example of a test. 214func (suite *SuiteTester) TestTwo() { 215 beforeCount := suite.TestTwoRunCount 216 suite.TestTwoRunCount++ 217 assert.NotEqual(suite.T(), suite.TestTwoRunCount, beforeCount) 218 suite.NotEqual(suite.TestTwoRunCount, beforeCount) 219} 220 221func (suite *SuiteTester) TestSkip() { 222 suite.T().Skip() 223} 224 225// NonTestMethod does not begin with "Test", so it will not be run by 226// testify as a test in the suite. This is useful for creating helper 227// methods for your tests. 228func (suite *SuiteTester) NonTestMethod() { 229 suite.NonTestMethodRunCount++ 230} 231 232func (suite *SuiteTester) TestSubtest() { 233 suite.TestSubtestRunCount++ 234 235 for _, t := range []struct { 236 testName string 237 }{ 238 {"first"}, 239 {"second"}, 240 } { 241 suiteT := suite.T() 242 suite.Run(t.testName, func() { 243 // We should get a different *testing.T for subtests, so that 244 // go test recognizes them as proper subtests for output formatting 245 // and running individual subtests 246 subTestT := suite.T() 247 suite.NotEqual(subTestT, suiteT) 248 }) 249 suite.Equal(suiteT, suite.T()) 250 } 251} 252 253type SuiteSkipTester struct { 254 // Include our basic suite logic. 255 Suite 256 257 // Keep counts of how many times each method is run. 258 SetupSuiteRunCount int 259 TearDownSuiteRunCount int 260} 261 262func (suite *SuiteSkipTester) SetupSuite() { 263 suite.SetupSuiteRunCount++ 264 suite.T().Skip() 265} 266 267func (suite *SuiteSkipTester) TestNothing() { 268 // SetupSuite is only called when at least one test satisfies 269 // test filter. For this suite to be set up (and then tore down) 270 // it is necessary to add at least one test method. 271} 272 273func (suite *SuiteSkipTester) TearDownSuite() { 274 suite.TearDownSuiteRunCount++ 275} 276 277// TestRunSuite will be run by the 'go test' command, so within it, we 278// can run our suite using the Run(*testing.T, TestingSuite) function. 279func TestRunSuite(t *testing.T) { 280 suiteTester := new(SuiteTester) 281 Run(t, suiteTester) 282 283 // Normally, the test would end here. The following are simply 284 // some assertions to ensure that the Run function is working as 285 // intended - they are not part of the example. 286 287 // The suite was only run once, so the SetupSuite and TearDownSuite 288 // methods should have each been run only once. 289 assert.Equal(t, suiteTester.SetupSuiteRunCount, 1) 290 assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1) 291 292 assert.Equal(t, len(suiteTester.SuiteNameAfter), 4) 293 assert.Equal(t, len(suiteTester.SuiteNameBefore), 4) 294 assert.Equal(t, len(suiteTester.TestNameAfter), 4) 295 assert.Equal(t, len(suiteTester.TestNameBefore), 4) 296 297 assert.Contains(t, suiteTester.TestNameAfter, "TestOne") 298 assert.Contains(t, suiteTester.TestNameAfter, "TestTwo") 299 assert.Contains(t, suiteTester.TestNameAfter, "TestSkip") 300 assert.Contains(t, suiteTester.TestNameAfter, "TestSubtest") 301 302 assert.Contains(t, suiteTester.TestNameBefore, "TestOne") 303 assert.Contains(t, suiteTester.TestNameBefore, "TestTwo") 304 assert.Contains(t, suiteTester.TestNameBefore, "TestSkip") 305 assert.Contains(t, suiteTester.TestNameBefore, "TestSubtest") 306 307 for _, suiteName := range suiteTester.SuiteNameAfter { 308 assert.Equal(t, "SuiteTester", suiteName) 309 } 310 311 for _, suiteName := range suiteTester.SuiteNameBefore { 312 assert.Equal(t, "SuiteTester", suiteName) 313 } 314 315 for _, when := range suiteTester.TimeAfter { 316 assert.False(t, when.IsZero()) 317 } 318 319 for _, when := range suiteTester.TimeBefore { 320 assert.False(t, when.IsZero()) 321 } 322 323 // There are four test methods (TestOne, TestTwo, TestSkip, and TestSubtest), so 324 // the SetupTest and TearDownTest methods (which should be run once for 325 // each test) should have been run four times. 326 assert.Equal(t, suiteTester.SetupTestRunCount, 4) 327 assert.Equal(t, suiteTester.TearDownTestRunCount, 4) 328 329 // Each test should have been run once. 330 assert.Equal(t, suiteTester.TestOneRunCount, 1) 331 assert.Equal(t, suiteTester.TestTwoRunCount, 1) 332 assert.Equal(t, suiteTester.TestSubtestRunCount, 1) 333 334 // Methods that don't match the test method identifier shouldn't 335 // have been run at all. 336 assert.Equal(t, suiteTester.NonTestMethodRunCount, 0) 337 338 suiteSkipTester := new(SuiteSkipTester) 339 Run(t, suiteSkipTester) 340 341 // The suite was only run once, so the SetupSuite and TearDownSuite 342 // methods should have each been run only once, even though SetupSuite 343 // called Skip() 344 assert.Equal(t, suiteSkipTester.SetupSuiteRunCount, 1) 345 assert.Equal(t, suiteSkipTester.TearDownSuiteRunCount, 1) 346 347} 348 349// This suite has no Test... methods. It's setup and teardown must be skipped. 350type SuiteSetupSkipTester struct { 351 Suite 352 353 setUp bool 354 toreDown bool 355} 356 357func (s *SuiteSetupSkipTester) SetupSuite() { 358 s.setUp = true 359} 360 361func (s *SuiteSetupSkipTester) NonTestMethod() { 362 363} 364 365func (s *SuiteSetupSkipTester) TearDownSuite() { 366 s.toreDown = true 367} 368 369func TestSkippingSuiteSetup(t *testing.T) { 370 suiteTester := new(SuiteSetupSkipTester) 371 Run(t, suiteTester) 372 assert.False(t, suiteTester.setUp) 373 assert.False(t, suiteTester.toreDown) 374} 375 376func TestSuiteGetters(t *testing.T) { 377 suite := new(SuiteTester) 378 suite.SetT(t) 379 assert.NotNil(t, suite.Assert()) 380 assert.Equal(t, suite.Assertions, suite.Assert()) 381 assert.NotNil(t, suite.Require()) 382 assert.Equal(t, suite.require, suite.Require()) 383} 384 385type SuiteLoggingTester struct { 386 Suite 387} 388 389func (s *SuiteLoggingTester) TestLoggingPass() { 390 s.T().Log("TESTLOGPASS") 391} 392 393func (s *SuiteLoggingTester) TestLoggingFail() { 394 s.T().Log("TESTLOGFAIL") 395 assert.NotNil(s.T(), nil) // expected to fail 396} 397 398type StdoutCapture struct { 399 oldStdout *os.File 400 readPipe *os.File 401} 402 403func (sc *StdoutCapture) StartCapture() { 404 sc.oldStdout = os.Stdout 405 sc.readPipe, os.Stdout, _ = os.Pipe() 406} 407 408func (sc *StdoutCapture) StopCapture() (string, error) { 409 if sc.oldStdout == nil || sc.readPipe == nil { 410 return "", errors.New("StartCapture not called before StopCapture") 411 } 412 os.Stdout.Close() 413 os.Stdout = sc.oldStdout 414 bytes, err := ioutil.ReadAll(sc.readPipe) 415 if err != nil { 416 return "", err 417 } 418 return string(bytes), nil 419} 420 421func TestSuiteLogging(t *testing.T) { 422 suiteLoggingTester := new(SuiteLoggingTester) 423 capture := StdoutCapture{} 424 internalTest := testing.InternalTest{ 425 Name: "SomeTest", 426 F: func(subT *testing.T) { 427 Run(subT, suiteLoggingTester) 428 }, 429 } 430 capture.StartCapture() 431 testing.RunTests(allTestsFilter, []testing.InternalTest{internalTest}) 432 output, err := capture.StopCapture() 433 require.NoError(t, err, "Got an error trying to capture stdout and stderr!") 434 require.NotEmpty(t, output, "output content must not be empty") 435 436 // Failed tests' output is always printed 437 assert.Contains(t, output, "TESTLOGFAIL") 438 439 if testing.Verbose() { 440 // In verbose mode, output from successful tests is also printed 441 assert.Contains(t, output, "TESTLOGPASS") 442 } else { 443 assert.NotContains(t, output, "TESTLOGPASS") 444 } 445} 446