使用SDL

问题描述

背景

这是我第一次用C ++编写单元测试。我正在使用Catch2作为测试框架,并且在Visual Studio解决方案中设置了2个项目:一个用于我的应用程序,另一个用于测试。

我有一个要测试的简单游戏循环。像这样:

Application.h

#ifndef APPLICATION_H
#define APPLICATION_H

namespace Rival {

    class Application {
    public:
        void start();
    };

}  // namespace Rival

#endif  // APPLICATION_H

Application.cpp

#include "pch.h"
#include "Application.h"

#include <SDL.h>

namespace Rival {

    void Application::start() {
        Uint32 nextUpdateDue = SDL_GetTicks();
        while (!exiting) {
            Uint32 frameStartTime = SDL_GetTicks();

            if (nextUpdateDue <= frameStartTime) {
                // Update the game logic,as many times as necessary to keep it
                // in-sync with the refresh rate.
                while (nextUpdateDue <= frameStartTime) {
                    state->update();
                    nextUpdateDue += TimerUtils::timestepMs;
                }
                state->render();

            } else {
                // Sleep until next frame is due
                Uint32 sleepTime = nextUpdateDue - frameStartTime;
                SDL_Delay(sleepTime);
            }
        }
    }

}  // namespace Rival

问题

问题出在#include <SDL.h>

我希望能够从此标头中模拟方法,例如SDL_GetTicks()

如果可以帮助,我实际上不想 包括SDL;我想让单元测试轻巧,并且不受任何窗口创建/渲染代码的影响。

通常如何完成?

解决方法

答案是应用Fundamental Theorem of Software Engineering,它表示您可以通过添加新的抽象层来解决几乎所有问题。

这意味着您将SDL调用包装在可以在测试时换出的类中。定义一个接口(抽象基类),然后实现一个使用SDL的派生类,并实现另一个(或使用一个模拟对象)进行测试。只有SDL实现会了解SDL,因此测试甚至不会包含或链接它。

BTW,有关C ++测试的重要摘要,请参见this episode of CppCast on designing for test

,

最后,我通过对所使用的库函数进行存根来解决了这个问题。您可以使用有效的测试实现here找到我的提交。

这有点类似于@metal的建议,但是我没有添加新的抽象层,而是依靠我的测试项目不包含库头的事实,这意味着我可以自由提供我自己的替代品,用于测试。

也许我在过程中产生的文档会帮助其他人:

测试项目包含Main-Project定义的所有标头,但包含第三方库的标头。这是为了使测试轻巧。我们不想每次运行测试时都创建一个OpenGL上下文。

这意味着我们必须为依赖的任何第三方定义提供存根实现。还可以为严重依赖第三方库的文件(例如Texture)提供Main-Project定义的存根或模拟实现。可以根据需要将Main-Project中的其他源文件直接包含在测试项目中。

为使项目井井有条,已创建了多个过滤器:

  • 测试框架::运行测试所需的文件。
  • 源文件:未经测试的未经修改的源文件,直接从Main-Project导入。
  • 测试双打: Main-Project标头的仅测试实现。
  • 测试:测试本身。

顺便说一句,到目前为止,Catch2框架非常出色,并且没有增加任何额外的复杂性。