class_docstr: Check functionality of optimization loop.
code: def test_invalid_arms_per_trial(self) -> None:
      with self.assertRaisesRegex(
          UserInputError, "Invalid number of arms per trial: 0"
      ):
          loop = OptimizationLoop.with_evaluation_function(
              parameters=[
                  {
                      "name": "x1",
                      "type": "range",
                      "bounds": [-10.0, 10.0],
                  },
                  {
                      "name": "x2",
                      "type": "range",
                      "bounds": [-10.0, 10.0],
                  },
              ],
              experiment_name="test",
              objective_name="foo",
              evaluation_function=lambda p: 0.0,
              minimize=True,
              total_trials=5,
              arms_per_trial=0,
          )
          loop.run_trial()
  
imports: from typing import Dict, Tuple, Union
  from unittest.mock import Mock, patch
  import numpy
  from ax.exceptions.core import UserInputError
  from ax.metrics.branin import branin
  from ax.modelbridge.generation_strategy import GenerationStep, GenerationStrategy
  from ax.modelbridge.registry import Models
  from ax.service.managed_loop import OptimizationLoop, optimize
  from ax.utils.common.testutils import TestCase
  from ax.utils.testing.mock import fast_botorch_optimize
  from numpy import ndarray
label_desc: Use image node_id 15 for calling the TestManagedLoop obj's underlying member method code with example usage: obj.test_invalid_arms_per_trial() without return types