def on_test_batch_end(
        self,
        trainer: Trainer,
        pl_module: AnomalibModule,
        outputs: STEP_OUTPUT | None,
        batch: Any,  # noqa: ANN401
        batch_idx: int,
        dataloader_idx: int = 0,
    ) -> None:
        """Generate visualizations at the end of a test batch.

        Args:
            trainer (Trainer): PyTorch Lightning trainer instance.
            pl_module (AnomalibModule): The current module being tested.
            outputs (STEP_OUTPUT | None): Outputs from the test step.
            batch (Any): Current batch of data.
            batch_idx (int): Index of the current batch.
            dataloader_idx (int, optional): Index of the dataloader. Defaults to 0.

        Example:
            Generate visualizations for a test batch::

                >>> from anomalib.utils.visualization import ImageVisualizer
                >>> callback = _VisualizationCallback(
                ...     visualizers=ImageVisualizer(),
                ...     save=True,
                ...     root="results/images"
                ... )
                >>> callback.on_test_batch_end(trainer, model, outputs, batch, 0)

        Raises:
            ValueError: If ``save`` is ``True`` but ``file_name`` is ``None``.
        """
        for generator in self.generators:
            if generator.visualize_on == VisualizationStep.BATCH:
                for result in generator(
                    trainer=trainer,
                    pl_module=pl_module,
                    outputs=outputs,
                    batch=batch,
                    batch_idx=batch_idx,
                    dataloader_idx=dataloader_idx,
                ):
                    if self.save:
                        if result.file_name is None:
                            msg = "``save`` is set to ``True`` but file name is ``None``"
                            raise ValueError(msg)

                        # Get the filename to save the image.
                        # Filename is split based on the datamodule name and category.
                        # For example, if the filename is `MVTec/bottle/000.png`, then the
                        # filename is split based on `MVTec/bottle` and `000.png` is saved.
                        if trainer.datamodule is not None:
                            filename = str(result.file_name).split(
                                sep=f"{trainer.datamodule.name}/{trainer.datamodule.category}",
                            )[-1]
                        else:
                            filename = Path(result.file_name).name
                        save_image(image=result.image, root=self.root, filename=filename)
                    if self.show:
                        show_image(image=result.image, title=str(result.file_name))
                    if self.log:
                        self._add_to_logger(result, pl_module, trainer)
Generate visualizations at the end of a test batch.

        Args:
            trainer (Trainer): PyTorch Lightning trainer instance.
            pl_module (AnomalibModule): The current module being tested.
            outputs (STEP_OUTPUT | None): Outputs from the test step.
            batch (Any): Current batch of data.
            batch_idx (int): Index of the current batch.
            dataloader_idx (int, optional): Index of the dataloader. Defaults to 0.

        Example:
            Generate visualizations for a test batch::

                >>> from anomalib.utils.visualization import ImageVisualizer
                >>> callback = _VisualizationCallback(
                ...     visualizers=ImageVisualizer(),
                ...     save=True,
                ...     root="results/images"
                ... )
                >>> callback.on_test_batch_end(trainer, model, outputs, batch, 0)

        Raises:
            ValueError: If ``save`` is ``True`` but ``file_name`` is ``None``.
        
src/anomalib/callbacks/visualizer.py