简体   繁体   English

如何为 cocos2d 应用程序设置单元测试?

[英]How to Setup Unit Tests for cocos2d apps?

I have been trying to figure out how to setup OCUnit unit tests for my game that uses cocos2d.我一直在试图弄清楚如何为我使用 cocos2d 的游戏设置OCUnit单元测试。 So I followed these instructions to set up the test target initially: http://blog.shalomfriss.com/?p=894所以我按照这些说明最初设置了测试目标: http : //blog.shalomfriss.com/?p=894

Unfortunately, the code below triggers a signal SIGABRT when I run the test through Product > Test in Xcode.不幸的是,当我通过Xcode. Product > Test 运行测试时,下面的代码会触发信号SIGABRT Xcode. The function where it breaks seems to be at [CCGLProgram compileShader:type:byteArray:]它中断的函数似乎在[CCGLProgram compileShader:type:byteArray:]

@implementation GameTests

- (void)setUp
{
    [super setUp];
}

- (void)tearDown
{
    // Tear-down code here.

    [super tearDown];
}

- (void)testExample
{
    STAssertNotNil([InitialLayer scene], @"initial layer scene was null.");
}

@end

This is the scene method from InitialLayer:这是来自 InitialLayer 的场景方法:

+(CCScene *) scene
{
    CCScene *scene = [CCScene node];
    InitialLayer*layer = [InitialLayernode];

    [scene addChild: layer];

    return scene;
}

Some other possibly relevant info:其他一些可能相关的信息:

  • target device: ipad 6.1目标设备:ipad 6.1
  • xcode version: 4.6.3 xcode版本:4.6.3
  • cocos2d version 2.1 cocos2d 2.1 版本

Does anyone know how to fix this or is there a better way in general to setup the tests using OCUnit or any other testing framework?有谁知道如何解决这个问题,或者有没有更好的方法来使用 OCUnit 或任何其他测试框架来设置测试?

You don't want to unit test anything cocos2d-related.您不想对与 cocos2d 相关的任何内容进行单元测试。 Without properly setting up the cocos2d CCGLView, the Director, and so on (the code that goes in the app delegate) in the setUp method that won't work to begin with.如果没有在 setUp 方法中正确设置 cocos2d CCGLView、Director 等(应用程序委托中的代码),将无法开始。

Even when you do set it up, you always will be testing cocos2d itself, which will make your tests less isolated and you're almost required to set up a fresh new scene for each test in order to test any code in subclassed nodes.即使您进行了设置,您也始终会测试 cocos2d 本身,这将使您的测试不那么孤立,并且您几乎需要为每个测试设置一个全新的场景,以便测试子类节点中的任何代码。 Which means the time to write tests as well as how long each test runs quickly grows.这意味着编写测试的时间以及每个测试运行的时间会快速增长。

Further complicating matters is that cocos2d's updates are tied to the CADisplayLink updates, and I'm not even sure they get fired when running a unit test.更复杂的是,cocos2d 的更新与 CADisplayLink 更新相关联,我什至不确定它们在运行单元测试时是否会被触发。 Even when updates do fire, you can't test them because a unit test runs once and ends, it has no concept "runs over a certain period of time".即使更新确实触发,您也无法测试它们,因为单元测试运行一次并结束,它没有“运行一段时间”的概念。 So something like "move a node to x,y and check that it got there after 3 seconds" is inherently not testable with the way cocos2d and unit tests work.因此,诸如“将节点移动到 x,y 并检查它是否在 3 秒后到达那里”之类的内容本质上无法使用 cocos2d 和单元测试的工作方式进行测试。 At least not without heavily modifying cocos2d itself.至少在没有大量修改 cocos2d 本身的情况下。

If you consider that cocos2d represents the view of your app, the real question is: why would you even want to unit test anything view-related in the first place?如果您认为 cocos2d 代表您的应用程序的视图,那么真正的问题是:您为什么要首先对任何与视图相关的内容进行单元测试?

Instead what you can do is to design your classes completely independent of the view.相反,您可以做的是设计完全独立于视图的类。 For example you can create extra game logic classes that are added to a node's userObject property and then control the node - the actual testable game logic happens in the model classes.例如,您可以创建添加到节点的 userObject 属性的额外游戏逻辑类,然后控制该节点 - 实际可测试的游戏逻辑发生在模型类中。 You can have additional controller classes which fire off things like running animations, or particle effects, and any other view-related stuff that doesn't need to be tested - because at worst it won't look right, but it won't affect the gameplay.你可以有额外的控制器类来触发诸如运行动画或粒子效果之类的东西,以及任何其他不需要测试的与视图相关的东西 - 因为在最坏的情况下它看起来不正确,但它不会影响游戏玩法。

One of the key benefits of test-driven development is to make classes testable, and that means not making them depend on the view.测试驱动开发的主要好处之一是使类可测试,这意味着不使它们依赖于视图。 So your first goal should actually be to make tests that run without cocos2d.所以你的第一个目标实际上应该是在没有cocos2d 的情况下进行测试。

If you want to see how this can be done, check out OpenGW and specifically the class reference .如果您想了解如何做到这一点,请查看OpenGW ,特别是类参考 Besides pushing a game object's (OGWEntity) position and rotation to the view delegate (OGWNode) there's absolutely no dependency on view code.除了将游戏对象 (OGWEntity) 的位置和旋转推送到视图委托 (OGWNode) 之外,绝对不依赖于视图代码。 The intermediary class that performs actions on the view based on the entity's state is OGWController.根据实体的状态对视图执行操作的中间类是 OGWController。

All of this makes OpenGW a highly testable game simulation engine.所有这些使 OpenGW 成为一个高度可测试的游戏模拟引擎。 In fact it is so decoupled from anything view-related that I'm in the process of making the same code run with both Sprite Kit and cocos2d-iphone.事实上,它与任何与视图相关的东西都如此分离,以至于我正在使用 Sprite Kit 和 cocos2d-iphone 运行相同的代码。

I agree that a complete test for everything is a waste of time but it doesn't mean to avoid it completely.我同意对所有内容进行完整测试是浪费时间,但这并不意味着完全避免它。 It's good to separate your logic classes and methods and test them using the unit test to make sure that they are working correctly using gTest with modification to cmake.最好将您的逻辑类和方法分开并使用单元测试来测试它们,以确保它们使用 gTest 和 cmake 进行修改后正常工作。 I did unit testing for util and logic classes like this: I added this to end of my CMAKE file我对 util 和 logic 类进行了单元测试,如下所示:我将此添加到我的 CMAKE 文件的末尾

if(WINDOWS)

    set(UNIT_TEST_SOLUTION_NAME runUnitTests)

    FILE(GLOB_RECURSE USER_TEST "Classes/*.test.cpp")

    list(APPEND GAME_TEST
        ${USER_TEST}
        #${USER_HEADER}
        #${USER_CPP}
        Classes/utils/common_operators/CommonOperators.cpp
        Classes/utils/common_operators/CommonOperators.h
    )

    #list(FILTER GAME_TEST EXCLUDE REGEX "Classes/scenes/.*")
    #list(FILTER GAME_TEST EXCLUDE REGEX "AppDelegate.cpp")
    #list(FILTER GAME_TEST EXCLUDE REGEX "AppDelegate.h")
    #list(FILTER GAME_TEST EXCLUDE REGEX "Classes/text/persian_language_support/.*")

    set(run_unit_test_file
        ${GAME_TEST}
        proj.unit_test/main.cpp
    )

    #option(test "Build all tests." ON)
    enable_testing()

    find_package(GTest CONFIG REQUIRED)
    add_executable(${UNIT_TEST_SOLUTION_NAME} ${run_unit_test_file})
    target_link_libraries(runUnitTests GTest::gtest GTest::gtest_main GTest::gmock GTest::gmock_main)
    add_test(runUnitTests runUnitTests)
endif()

And example test file is :示例测试文件是:

#include "gtest/gtest.h"
#include "CommonOperators.h"

TEST(CommonOperators, split) {
    auto case1Result = CommonOperators::split("mamad reza masood", ' ');
    std::vector<std::string> case1ExpectedResult = { "mamad", "reza", "masood" };
    EXPECT_EQ(case1Result, case1ExpectedResult);
}

Please note that I downloaded google test (gTest) using vckpg and then placed its folder in my root directory.请注意,我使用 vckpg 下载了 google test (gTest),然后将其文件夹放在我的根目录中。 Another note: For running your test in windows you need to define new solution with name that is mentioned in your cmake test part.And also you need to create main file like following in a new directory另一个注意事项:要在 Windows 中运行测试,您需要使用 cmake 测试部分中提到的名称定义新解决方案。此外,您还需要在新目录中创建如下所示的主文件


#include "gtest/gtest.h"

int main(int argc, char** argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM