dwiza3962 / mff_auto

Game bot for Marvel Future Fight game.
Apache License 2.0
4 stars 1 forks source link

Unit tests for modules and UI #33

Closed tmarenko closed 2 years ago

tmarenko commented 2 years ago

Sorry that I didn't provide this earlier. In this archive you will find unittests for core functions and UI elements: https://drive.google.com/file/d/1Gg8NP5AQwvTlJSA5-a4FOeCfVU2LzPZh/view?usp=sharing I didn't store this in main repo because screenshots had private account information. Extract archive's content into the project's folder and run test either through Pycharm: image

or run run_tests.py If you run tests from run_test.py look at result.log in the same folder.

The most valuable test suite is test_tessract.py which tries to recognize UI element on different resolutions from screenshots unittests/test_images/ui_images folder. I know that some of screenshot are outdated by now. You can delete them from the folder and recapture again. To capture a propper screenshot update this methods in video_capture.py:

    @staticmethod
    def click_button_decorator(emulator, click_button):
        """emulator.click_button decorator for debug drawing of rectangle."""

        def wrapped(ui_element, **kwargs):
            global_rect = ui_element.button_rect.global_rect
            box = (global_rect[0] * emulator.width, global_rect[1] * emulator.height,
                   global_rect[2] * emulator.width, global_rect[3] * emulator.height)
            element = ElementOnScreen(name="", box=box, color=ElementOnScreen.RED_COLOR)
            if emulator.screen_elements is not None:
                emulator.screen_elements.append(element)
            if ui_element.name and not os.path.exists(f"unittests\\test_images\\ui_images\\{ui_element.name}.png"):
                while emulator.screen_locked:
                    pass
                emulator._get_screen().copy().save(f"unittests\\test_images\\ui_images\\{ui_element.name}.png")
            return click_button(ui_element=ui_element, **kwargs)

        return wrapped

    @staticmethod
    def is_ui_element_on_screen_decorator(emulator, is_ui_element_on_screen):
        """emulator.is_ui_element_on_screen decorator for debug drawing of rectangle."""

        def wrapped(ui_element, screen=None):
            on_screen = is_ui_element_on_screen(ui_element=ui_element, screen=screen)
            elements = [element for element in emulator.screen_elements if element.name == ui_element.name]
            for element in elements:
                if emulator.screen_elements is not None and on_screen:
                    element.color = ElementOnScreen.MAGENTA_COLOR
                    emulator.screen_elements.append(element)
            if on_screen and not os.path.exists(f"unittests\\test_images\\ui_images\\{ui_element.name}.png"):
                while emulator.screen_locked:
                    pass
                emulator._get_screen().copy().save(f"unittests\\test_images\\ui_images\\{ui_element.name}.png")
            return on_screen

        return wrapped

    @staticmethod
    def is_image_on_screen_decorator(emulator, is_image_on_screen):
        """emulator.is_image_on_screen decorator for debug drawing of image rectangle."""

        def wrapped(ui_element, screen=None):
            box = (ui_element.image_rect.global_rect[0] * emulator.width,
                   ui_element.image_rect.global_rect[1] * emulator.height,
                   ui_element.image_rect.global_rect[2] * emulator.width,
                   ui_element.image_rect.global_rect[3] * emulator.height)
            element = ElementOnScreen(name=ui_element.name, box=box, color=ElementOnScreen.CYAN_COLOR)
            on_screen = is_image_on_screen(ui_element=ui_element, screen=screen)
            element.color = ElementOnScreen.MAGENTA_COLOR if on_screen else element.color
            if emulator.screen_elements is not None:
                emulator.screen_elements.append(element)
            if on_screen and not os.path.exists(f"unittests\\test_images\\ui_images\\{ui_element.name}.png"):
                while emulator.screen_locked:
                    pass
                emulator._get_screen().copy().save(f"unittests\\test_images\\ui_images\\{ui_element.name}.png")
            return on_screen

        return wrapped

and run game mode with required UI with enabled video capture. As you can see:

            if on_screen and not os.path.exists(f"unittests\\test_images\\ui_images\\{ui_element.name}.png"):
                while emulator.screen_locked:
                    pass
                emulator._get_screen().copy().save(f"unittests\\test_images\\ui_images\\{ui_element.name}.png")

this lines make sure that image would be stored only if UI was recognized and there is already no screenshot in the folder. This method helps to recapture multiple UI elements at one run but you can write your own function if you want to capture just one element from current screen:

from lib.emulators.nox_player import NoxPlayer
nox = NoxPlayer("NoxPlayer")._get_screen().save('ui_name.png')

I used emulator._get_screen().copy().save because the screenshot would be the same structure as the bot sees the screen. Also all of the screenshots were saved in 1080p with HIGH quality graphics. It helps to tune threshold parameter for every resolution.

If you have any question about test cases and their logic feel free to ask.

dwiza3962 commented 2 years ago

Thank you @tmarenko . I went down a rabbit hole of trying to upgrade to the latest python, nox, then upgraded packages and back to where I started. So I haven't gotten a chance to take a look at this. I'm back to an operational state and will give this a go.