code: def testValidateMetricsMetricTDistributionChangeAndThreshold(
      self, slicing_specs, slice_key
  ):
      threshold = config_pb2.MetricThreshold(
          change_threshold=config_pb2.GenericChangeThreshold(
              direction=config_pb2.MetricDirection.LOWER_IS_BETTER,
              absolute={"value": -1},
          )
      )
      eval_config = config_pb2.EvalConfig(
          model_specs=[
              config_pb2.ModelSpec(),
              config_pb2.ModelSpec(name="baseline", is_baseline=True),
          ],
          slicing_specs=slicing_specs,
          metrics_specs=[
              config_pb2.MetricsSpec(
                  metrics=[
                      config_pb2.MetricConfig(
                          class_name="AUC",
                          threshold=threshold
                          if slicing_specs is None
                          else None,
                          per_slice_thresholds=[
                              config_pb2.PerSliceMetricThreshold(
                                  slicing_specs=slicing_specs,
                                  threshold=threshold,
                              )
                          ],
                      ),
                  ],
                  model_names=[""],
              ),
          ],
      )
      sliced_metrics = (
          slice_key,
          {
              # This is the mean of the diff.
              metric_types.MetricKey(
                  name="auc", model_name="baseline"
              ): types.ValueWithTDistribution(
                  sample_mean=0.91, unsampled_value=0.6
              ),
              metric_types.MetricKey(
                  name="auc", is_diff=True
              ): types.ValueWithTDistribution(
                  sample_mean=0.1, unsampled_value=0.1
              ),
          },
      )
      result = metrics_validator.validate_metrics(
          sliced_metrics, eval_config
      )
      self.assertFalse(result.validation_ok)
      expected = text_format.Parse(
          """
          metric_validations_per_slice {
            failures {
              metric_key {
                name: "auc"
                is_diff: true
                example_weighted { }
              }
              metric_value {
                double_value {
                  value: 0.1
                }
              }
            }
          }""",
          validation_result_pb2.ValidationResult(),
      )
      expected.metric_validations_per_slice[0].failures[
          0
      ].metric_threshold.CopyFrom(threshold)
      expected.metric_validations_per_slice[0].slice_key.CopyFrom(
          slicer.serialize_slice_key(slice_key)
      )
      for spec in slicing_specs or [None]:
          if spec is None or slicer.SingleSliceSpec(
              spec=spec
          ).is_slice_applicable(slice_key):
              slicing_details = (
                  expected.validation_details.slicing_details.add()
              )
              if spec is not None:
                  slicing_details.slicing_spec.CopyFrom(spec)
              else:
                  slicing_details.slicing_spec.CopyFrom(
                      config_pb2.SlicingSpec()
                  )
              slicing_details.num_matching_slices = 1
      self.assertAlmostEqual(result, expected)
  
imports: from absl.testing import parameterized
  import tensorflow
  from tensorflow_model_analysis.api import types
  from tensorflow_model_analysis.eval_saved_model import testutil
  from tensorflow_model_analysis.evaluators import metrics_validator
  from tensorflow_model_analysis.metrics import metric_types
  from tensorflow_model_analysis.proto import config_pb2
  from tensorflow_model_analysis.proto import validation_result_pb2
  from tensorflow_model_analysis.slicer import slicer_lib
  from google.protobuf import text_format
label_desc: Use image node_id 3 for calling the MetricsValidatorTest obj's underlying member method code with example usage: obj.testValidateMetricsMetricTDistributionChangeAndThreshold(slicing_specs, slice_key) without return types