0

I have two goroutines which are two TestXxx functions during the testing. I use a conditional variable to synchronize these goroutines. However, once one of them fails the test while the other one is waiting for the signal. Here comes a deadlock. Also, I want TestFunctionA to be failed if TestFunctionB is failed.

var cond sync.Cond
func TestFunctionA(t *testing.T){
   // ... Some codes...
   cond.Wait()
}
func TestFunctionB(t *testing.T){
   // ... Some codes...
   t.Fail()
   // ... Some codes...
   cond.Broadcast()
}

I've tried some ways, for example:

var cond sync.Cond
var A_t *testing.T
func TestFunctionA(t *testing.T){
   // ... Some codes...
   A_t = t
   // ... Some codes...
   cond.Wait()
}
func TestFunctionB(t *testing.T){
   // ... Some codes...
   t.Cleanup(func(){
      if !A_t.Failed(){
          A_t.Fail()
      }
      cond.Broadcast()
   })
   t.Fail()
   // ... Some codes...
   cond.Broadcast()
}

But the A_t.Fail() is still triggered when there is no error in FunctionB.

And I'm also considering using context.Context(). However, I have no idea how to run a Testfunction with a context. Thank you for reading my question! I appreciate any comment or discussion!

WeiAnHsieh
  • 33
  • 4
  • 1
    First of all, a test should not interact with another test. There must be something wrong if you need to do this. Maybe you want to write a single test instead. – Zeke Lu May 22 '23 at 03:37

1 Answers1

0

A test should not interact with another test. But we can share anything between test cases when using subtests.

Here is an example:

package main

import (
    "errors"
    "testing"
)

func TestFruits(t *testing.T) {
    var err error
    t.Run("test apple", getTestAppleFunc(&err))
    t.Run("test banana", getTestBananaFunc(&err))
}

func handleError(t *testing.T, err *error) {
    if err != nil && *err != nil {
        t.Error(*err)
    }
}

func getTestAppleFunc(err *error) func(*testing.T) {
    return func(t *testing.T) {
        handleError(t, err)
        *err = errors.New("Apple failed")
    }
}

func getTestBananaFunc(err *error) func(*testing.T) {
    return func(t *testing.T) {
        handleError(t, err)
    }
}
  • In the functions getTestBananaFunc and getTestAppleFunc, the pointer of error is passed as an argument.
  • In the above example, getTestAppleFunc is executed first.
  • If an error is assigned in getTestAppleFunc, as shown in the above example, the getTestBananaFunc function will fail.
  • Thank you for answering! My requirement of testing is that different TestXxx functions needs to be run in parallel and also synchronize with each other. Maybe subTest also works for this scenario. However, I need the original *testing.T for the name. When I use t.Logf, I might call t.Name() as a mark. I'm not sure if subtest could finish this job... – WeiAnHsieh May 25 '23 at 03:55