SFML community forums

General => SFML development => Topic started by: Tank on August 26, 2014, 10:01:34 am

Title: Unit tests
Post by: Tank on August 26, 2014, 10:01:34 am
Hey guys,

I finally had some time to add the Catch framework together with one unit test example to the repository. You can find it here: https://github.com/SFML/SFML/commits/feature/unittest

I've used the BDD style as I find it to be incredibly readable. I think we should agree on the style first before I continue writing tests. I don't want to change millions of test cases. ;)
Title: Re: Unit tests
Post by: Laurent on August 26, 2014, 10:10:10 am
It looks really good :)

I don't know the Catch framework so I trust you for the style. However I'm curious to see how it looks with more complex test cases.

Also, have you started to think about the continuous integration server, and about a framework for testing graphical stuff? (what? I'm asking too much? ;D)
Title: Re: Unit tests
Post by: Tank on August 26, 2014, 10:53:10 am
Quote from: Laurent
I don't know the Catch framework so I trust you for the style.
Catch supports another style as well, which is more technical. BDD has the advantage of being very readable, expressive and descriptive, and it makes you think about your problem ("What do I really need?").

Quote from: Laurent
However I'm curious to see how it looks with more complex test cases.
You are not the only one who's curious. ;) One issue is that SFML hasn't been developed with testability in mind, so it will be quite difficult in some spots. Maybe some refactorings here and there will be required. But we'll see how that will come along.

Quote from: Laurent
Also, have you started to think about the continuous integration server, and about a framework for testing graphical stuff?
You mean this (http://build.sfml-dev.de/waterfall)? ;) It's right now building the master branch, but I'd like to change the infrastructure a bit to make it better extendable. zsbzsb will be contributing a FreeBSD box. A Windows 7 box is already available, but not yet connected to CI.

Quote from: Laurent
(what? I'm asking too much? ;D)
No. :)
Title: Re: Unit tests
Post by: Laurent on August 26, 2014, 10:58:35 am
Quote
You mean this?
Ooohhh... it seems that everybody but me knew it. Was it announced somewhere? :P

I still have a Windows 7 and a Mac OS X 10.7 available if you need.
Title: Re: Unit tests
Post by: Hiura on August 26, 2014, 10:59:23 am
Good job!

There's something wrong on OS X though. But that's my headache, not yours.  ;)
(click to show/hide)

I've just one question: how safe is it to modify a variable that is used in several WHEN cases? I'm more specifically thinking of line 144 and 166 (https://github.com/SFML/SFML/blob/1507bb87917b7a56ff1111b5ac767c1c9143d5fb/test/src/Vector2.cpp#L142-L173) and how they might mess with each other. Does the Catch framework take care of this with some black magic?

You mean this (http://build.sfml-dev.de/waterfall)? ;)
Wow! That's nice :D
Title: Re: Unit tests
Post by: Laurent on August 26, 2014, 11:05:25 am
Quote
I've just one question: how safe is it to modify a variable that is used in several WHEN cases? I'm more specifically thinking of line 144 and 166 and how they might mess with each other. Does the Catch framework take care of this with some black magic?
I was reading the tutorial so I can answer your question: each WHEN triggers a new call (don't know from where it restarts), so they are self-contained and cannot mess up other sections.
Title: Re: Unit tests
Post by: Tank on August 26, 2014, 11:09:37 am
@Hiura
That error is probably related to the linker not being able to find the library files. Try adding a link_directories( "${PROJECT_BIN_PATH}/lib" ). Just a quick shot, though. ;)

As Laurent said, it's safe to use the variables like that -- it's actually encouraged and a replacement for the otherwise traditional setup/tear down machanism (which is very annoying to write, to be honest).
Title: Re: Unit tests
Post by: Hiura on August 26, 2014, 11:12:09 am
Okay! That's a nice feature   :)

@Tank, unfortunately it doesn't solve the problem but I might know why. I'll have a look probably next week.
Title: Re: Unit tests
Post by: Hiura on October 03, 2014, 08:24:01 am
...And I completely forgot about that... -> on my TODO list!

BTW, do we have a OS X system setup for the automatic build? If needed I could run from time to time a VM on my laptop that would communicate with the server (if someone explain me a bit how to do it of course). I guess I could launch it more than once a week (except for holidays). Would that be a good thing or do we look for a 100% uptime build machine?
Title: Re: Unit tests
Post by: Tank on October 03, 2014, 08:40:17 am
Every interval is better than no interval, but having CI would be the best, of course. ;)
Title: Re: Unit tests
Post by: Hiura on October 05, 2014, 07:26:12 pm
Alright, I've managed to make them run on OS X. You can find the changed on the feature/unittest_osx branch (https://github.com/SFML/SFML/tree/feature/unittest_osx). There's two commits: the first one fix the runtime settings on OS X (specifically, the search path for binaries is more flexible) and the second one fix the Xcode templates. I've also rebase the branch against master.

EDIT: don't rush in merging anything into feature/unittest. I just realised that I might need to integrated these commits to the no_libsndfile branch too if I don't want to do it twice. In this case the better would be to add them directly into master and rebase both branches. I'll come back to that in due time.

I expect the installation procedure of JSFML and SFML.net to change a bit but for a regular usage of SFML there's nothing extra to do.

Regarding `SFML_BUILD_TEST`, I would recommend setting the default value to false. Regular user should not be that interested in tests I think.

And finally, about this CI thing, I'm happy to share some of my CPU time. I just need to know how to do it. Or at least, where to start looking for information.  :)
Title: Re: Unit tests
Post by: Tank on October 06, 2014, 01:55:42 am
Thanks for the commits. As you suggested I'll wait for them to enter master. If that's not going to happen, just drop me a line and I'll integrate them. :)

Quote
Regarding `SFML_BUILD_TEST`, I would recommend setting the default value to false. Regular user should not be that interested in tests I think.
I thought about that but chose to do it like I've been doing it in all projects: Default = on. The reason is that what's tests are for. If there's something failing, then chances are relatively high that we will receive a report on the forums or bug tracker instead of an unrecognized bug.

The compile times are higher (especially when the test suite will be more complete), but there are no extra steps involved for the user, so I'd still suggest to run them by default.
Title: Re: Unit tests
Post by: Hiura on October 07, 2014, 11:55:31 am
FYI I've removed feature/unittest_osx to prevent any confusion.

About SFML_BUILD_TEST, what do the others think? I'm curious.  :)
Title: Re: Unit tests
Post by: Laurent on October 07, 2014, 12:04:12 pm
Tank, do you mean that unit tests will be run automatically as part of the compilation process of SFML? If so, people will hardly notice them, and we'll get very precise and complete reports in case something is wrong. However if they must be run manually, then I'm against compiling/installing them by default.
Title: Re: Unit tests
Post by: Tank on October 07, 2014, 12:28:03 pm
They will indeed be part of the build process, no manual steps required.
Title: Re: Unit tests
Post by: Nexus on October 07, 2014, 03:00:32 pm
You mean running the tests as part of the build, not only compiling them, right?

If so, this requires a script invoked as a post-build step, we probably would have to investigate how this can be done with CMake. But I'm not sure if it's very wise to run tests automatically, because people might not expect new applications to start when just compiling, and depending on the test, interaction with external file resources or even sockets would be necessary.
Title: Re: Unit tests
Post by: eXpl0it3r on October 07, 2014, 03:03:34 pm
It's not hard to add that to CMake. Also it's not hard to add another switch, which is checked by default and can be unchecked by the user.
Running tests after compilation is by now more or less a standard behavior, if users don't expect that even after they didn't uncheck the test build marker, then it's nothing we should be concerned about.
Title: Re: Unit tests
Post by: Hiura on October 07, 2014, 03:13:28 pm
I feel there's a misunderstanding on what is already implemented. Currently, when you do cmake followed by `make` (and not `make test`) you get:
$ make
[  1%] Built target SFML
[ 13%] Built target sfml-system
[ 41%] Built target sfml-window
[ 50%] Built target sfml-network
[ 74%] Built target sfml-graphics
[ 84%] Built target sfml-audio
[ 85%] Built target ftp
[ 86%] Built target opengl
[ 86%] Built target pong
[ 87%] Built target shader
[ 89%] Built target sockets
[ 90%] Built target sound
[ 91%] Built target sound-capture
[ 94%] Built target voip
[ 95%] Built target window
[ 98%] Built target cocoa
[100%] Built target sfmltest
Running test suite...===============================================================================
All tests passed (30 assertions in 2 test cases)

[100%] Built target runtests
 

unless you set the SFML_TEST (or whatever its name is, I forgot) to FALSE.
Title: Re: Unit tests
Post by: Tank on October 07, 2014, 06:33:02 pm
CMake provides us a platform-independent way of launching executables. And since we control the build, there's absolutely no issue with that.

Tests that are not being run are useless, that's why I enable them by default. There are no disadvantages for the user. He will probably even be happy to see it. ;)
Title: Re: Unit tests
Post by: Tank on October 07, 2014, 06:34:26 pm
Sorry, to clarify:

Build by default? Yes
Run after build by default? Yes
Mark build as failed when tests fail? Yes
Title: Re: Unit tests
Post by: Laurent on October 07, 2014, 09:56:21 pm
Quote
Build by default? Yes
Run after build by default? Yes
Mark build as failed when tests fail? Yes
Agreed at 100%.
Title: Re: Unit tests
Post by: Laurent on October 12, 2014, 04:11:44 pm
Any news about the Windows machines for the CI server?

It would be really nice to avoid this (https://github.com/SFML/SFML/issues/718) ;)
Title: Re: Unit tests
Post by: Tank on October 12, 2014, 06:56:54 pm
It's setup, but not yet configured for CI. Will do it in the upcoming week.
Title: Re: Unit tests
Post by: Nexus on April 14, 2015, 08:42:34 pm
Recently, I have experimented with Catch, and it's really great. It offers a lot of flexibility and is very smart at interpreting the code. The only unfortunate thing is that its header-only nature is really nice to get things up and running quickly, but leads to unnecessarily long compile times in long-term projects.

Anyway, I would be willing to contribute with some test cases.

I personally think the BDD-style testing is too verbose if applied rigorously.
SCENARIO("Constructing sf::Vector2")
{
    WHEN("default constructor is used")
    {
        sf::Vector2i vector;

        THEN("x and y are 0")
        {
            CHECK(vector.x == 0);
            CHECK(vector.y == 0);
        }
    }
}
vs.
SECTION("Default-constructing sf::Vector2 yields (0, 0)")
{
    sf::Vector2i vector;
    CHECK(vector.x == 0);
    CHECK(vector.y == 0);
}

It is absolutely obvious that we expect members to be zero after default construction, and one annotation in the SECTION macro is more than enough to describe it. In many cases, the CHECK expressions alone would suffice. Writing it three times in text over 13 lines feels to me like
++i; // increment i
that is, unnecessary noise, which makes code harder to read and more difficult to maintain. The simple sf::Vector2i test takes already 220 lines. Imagine how this explodes for other classes that have 15 no-brainer setters/getters, when you have to repeat the same verbosity again and again.

What I really love about Catch is that code written with it can be tremendously concise -- unlike awful test frameworks where you have to write class hierarchies and spend an insane amount of time for nothing. I suggest we exploit this advantage where possible, and I'm sure I'm much more motivated to write test cases if I'm not dealing with so much boilerplate. I would end up copy-pasting anyway, and that's never a good sign ;)

There may be more complex cases where we really need to state what was meant. BDD style is one option, but keep in mind the WHEN/THEN macros are semantically equivalent to SECTIONs, so we can achieve the same either way.

Edit: Even more extreme example:
        WHEN("equal vectors are tested for equality")
        {
            bool equal = (firstEqualVector == secondEqualVector);

            THEN("the result is true")
            {
                CHECK(equal == true);
            }
        }
vs.
SECTION("operator==") // do we really need to explain == semantics?
{
    CHECK(firstEqualVector == secondEqualVector);
}

Both the SECTION caption and the expression given to CHECK are visible in the output if the test fails, so that's already 2 times obvious :D

And apart from that, the second code is better because it contains the objects to check in the CHECK macro, allowing Catch to evaluate the operand's values. One would need to define a string output for sf::Vector2, but then one would immediately see where the implementation is broken aka "(3,3) == (3,3)", rather than just an unhelpful "false == true".
Title: Re: Unit tests
Post by: binary1248 on April 14, 2015, 08:53:43 pm
Nothing prevents us from writing our own wrapper/helpers/macros around Catch that makes our lives easier... If/When I eventually also start writing tests (e.g. for GL stuff), I would also prefer the second variant over the first one. Copy and pasting might make life easier, but if it has to always be done anyway, why not just alleviate the need for it all together? ;)
Title: Re: Unit tests
Post by: Tank on April 15, 2015, 11:52:56 am
Quote from: Nexus
The only unfortunate thing is that its header-only nature is really nice to get things up and running quickly, but leads to unnecessarily long compile times in long-term projects.
Have you split your runner file from your test cases? Because usually compiling the runner file (the one that contains the CATCH_CONFIG_MAIN macro) takes some time, only.

Quote from: Nexus
I personally think the BDD-style testing is too verbose if applied rigorously.
The verbosity is actually a strong point of BDD, but I agree that in many cases, the bloat is quite annoying. BDD helped me to learn a certain way of thinking of test cases. But now that I learned that, I don't need it anymore in favor of more compact test cases. ;-)

Just take care when naming your section names: The names should be unique.
Title: Re: Unit tests
Post by: Nexus on April 15, 2015, 01:40:42 pm
Have you split your runner file from your test cases? Because usually compiling the runner file (the one that contains the CATCH_CONFIG_MAIN macro) takes some time, only.
Yes, I had it separately. I was able to mitigate the long compile times by using MSVC precompiled headers, but it's still a workaround. Unfortunately, I can't precompile <Catch.hpp>, because it comes in different versions for runner and test-case files, so I just precompiled the standard headers used everywhere.


The verbosity is actually a strong point of BDD, but I agree that in many cases, the bloat is quite annoying. BDD helped me to learn a certain way of thinking of test cases. But now that I learned that, I don't need it anymore in favor of more compact test cases. ;-)
Glad you see it like this :)

What do others think? Do you like the compact way of writing test sections like
SECTION("Default-constructing sf::Vector2 yields (0, 0)")
{
    sf::Vector2i vector;
    CHECK(vector.x == 0);
    CHECK(vector.y == 0);
}

Would be nice to find an agreement soon, then I can start writing some tests :)


Just take care when naming your section names: The names should be unique.
Are you sure? The tutorial (https://github.com/philsquared/Catch/blob/master/docs/tutorial.md#what-did-we-do-here) says test names must be unique, it doesn't mention sections. Keeping section names locally unique is definitely a good idea though (locally = within the same test case).
Title: Re: Unit tests
Post by: Hiura on April 15, 2015, 01:54:29 pm
I'm on my phone right now so I'll keep it short but if needed I can extend on later.

I also quite like Catch. First, it's the only framework with which I hadn't any trouble (cppunit reporting false memory leak, gtest being just ugly, ...).

Regarding the style of tests, I also felt that BDD is too verbose. Regardless of the style the (optional) tagging system is also a good strength of catch.
Title: Re: Unit tests
Post by: Tank on April 15, 2015, 02:51:26 pm
@Nexus
I suggest removing the expected test results from the section description. The test itself is readable enough, and in case of errors, the expected values will be printed anyway. So maybe something like "Default-constructing sf::Vector2".

I really wonder that it's so slow on your hand. I haven't had any difficulties with compile times yet (both GCC and Clang).
Title: Re: Unit tests
Post by: Nexus on April 26, 2015, 04:13:05 pm
I rebased feature/unittest onto latest master and rewrote the Vector2 tests in a more concise way. Are you okay with this style?

Since there seems to be public interest (https://github.com/SFML/SFML/issues/623#issuecomment-96335726) in contributing, we should quickly agree on some basic rules for style and consistency. Please comment on this thread even if you're okay with everything.


Some proposals, please tell me where you disagree or what's missing:

1. A single Catch test case (TEST_CASE macro) should be used for a unit (class, group of functions, etc.) to test. I adapted the Vector2 example, which used 2 test cases.

2. Functionality is grouped hierarchically in Catch sections (SECTION macro). For example, the Vector2 example has the following hierarchy:
(click to show/hide)

3. Test case and section names are concise, but contain enough information to understand what is tested in their context. If C++ syntax (like operators) makes things clearer than text, use them. Avoid repetition of parent test cases/sections (e.g. don't mention "sf::Vector2" again inside the Vector2 test case).

4. For assertions, the CHECK macro is used. REQUIRE, which stops at the first failed assertion, is avoided. To check negative conditions, CHECK_FALSE is used. More info... (https://github.com/philsquared/Catch/blob/master/docs/assertions.md)


Where I'm not sure yet:

5. How do we test with external resources? Many SFML classes require files (textures, sounds, shaders...) to be loaded in order to function correctly. Is this a problem if the tests are run as part of the build command? Are there limitations to keep in mind?

6. Shall we write string conversions (https://github.com/philsquared/Catch/blob/master/docs/tostring.md) to debug failed assertions?
Title: Re: Unit tests
Post by: eXpl0it3r on April 26, 2015, 05:25:22 pm
Looks fine to me. About the test, I wonder though what's with sf::Vector2u and sf::Vector2f?
Title: Re: Unit tests
Post by: Hiura on April 26, 2015, 06:08:03 pm
Looks nice.  ;)

Regarding 1), I would add a tag to the test case (it can be as simple as the module being tested). This is nice if when working on something you want to run only a subset of tests.

Example:
TEST_CASE("sf::Vector2 class", "[system]")

Regarding 5), I guess we could duplicate some resources inside test/.

As for 6), I'd say we don't do it unless there's a bug and it's actually useful to have the output, unless someone really want to spent his time doing that  :P. And if needed, I'd go with a Catch::toString overload instead of overloading operator <<.
Title: Re: Unit tests
Post by: Nexus on April 27, 2015, 11:11:11 am
About the test, I wonder though what's with sf::Vector2u and sf::Vector2f?
Tank wrote the test for Vector2i and it should generalize to Vector2<T>, because there are no template specializations, so the type should behave the same.

There are of course cases where int and float behave differently, for example with division, floating precision (bigger floats are less precise in their decimal places), rounding errors and special values (NaN, infinity, ...). But I think for the idea of testing the Vector2<T> functionality it's okay.

Test coverage is not 100% anyway, since we cover only one particular value per operation. Consider
    SECTION("Comparison operations (two equal and one different vector)")
    {
        sf::Vector2i firstEqualVector(1, 5);
        sf::Vector2i secondEqualVector(1, 5);
        sf::Vector2i differentVector(6, 9);

        SECTION("vector == vector")
        {
            CHECK(firstEqualVector == secondEqualVector);
            CHECK_FALSE(firstEqualVector == differentVector);
        }

        SECTION("vector != vector")
        {
            CHECK(firstEqualVector != differentVector);
            CHECK_FALSE(firstEqualVector != secondEqualVector);
        }
    }

The following wrong implementation of operator!= would still pass this test:
template <typename T>
bool operator!= (const sf::Vector2<T>& lhs, const sf::Vector2<T>& rhs)
{
    return lhs.x != rhs.x;
}

Now, in my opinion we can be a bit pragmatic, especially for class templates like sf::Vector2 that have existed for ages, been used by thousands of people, and are very unlikely to change in the future.


Regarding 1), I would add a tag to the test case (it can be as simple as the module being tested). This is nice if when working on something you want to run only a subset of tests.
Good idea.


Regarding 5), I guess we could duplicate some resources inside test/.
Should we really waste the space (e.g. for music or fonts, it can quickly be a few MB)? Is Git smart regarding exact file duplicates?


As for 6), I'd say we don't do it unless there's a bug and it's actually useful to have the output, unless someone really want to spent his time doing that  :P.
Maybe one for the most fundamental types like vectors or rects are useful, but I don't think it makes sense to provide it for more complex classes like sf::Sprite, either. After all, string conversions are only invoked in a relational comparison, an operation that most SFML classes don't even support.
Title: Re: Unit tests
Post by: Hiura on April 27, 2015, 01:40:11 pm
Should we really waste the space (e.g. for music or fonts, it can quickly be a few MB)? Is Git smart regarding exact file duplicates?

No, git doesn't support such feature. But that shouldn't really be an issue: currently the whole examples directory, including source code and probably duplicate resources, weight ~1.5MB.

If someone really want to only download the head, without history, he can do a shallow clone with `--depth 1` which is result (today) in a <20 MB download instead of ~70MB (but he won't be able to push/pull in the future so it's simpler to download the zip archive directly).

 
Title: Re: Unit tests
Post by: Tank on April 28, 2015, 04:13:40 pm
Quote
4. For assertions, the CHECK macro is used. REQUIRE, which stops at the first failed assertion, is avoided. To check negative conditions, CHECK_FALSE is used. More info... (https://github.com/philsquared/Catch/blob/master/docs/assertions.md)
REQUIRE is especially useful when you want to make sure that certain critical test conditions are met. E.g.:

foo.add(123);
foo.add(456);
REQUIRE(foo.getCount() == 2);
CHECK(foo[0] == 123);
CHECK(foo[1] == 456);


Quote
5. How do we test with external resources? Many SFML classes require files (textures, sounds, shaders...) to be loaded in order to function correctly. Is this a problem if the tests are run as part of the build command? Are there limitations to keep in mind?
Everything that's needed for testing must be provided. Keep in mind that test resources are usually really small. E.g. a sound file that's exactly 1 second long and contains a specific set of data.

Quote
6. Shall we write string conversions (https://github.com/philsquared/Catch/blob/master/docs/tostring.md) to debug failed assertions?
Why not? It may greatly improve the readability of failed test reports.
Title: Re: Unit tests
Post by: Nexus on April 28, 2015, 08:54:24 pm
REQUIRE is especially useful when you want to make sure that certain critical test conditions are met.
That's a really good point. If I remember correctly, REQUIRE aborts the whole test case, not just the current section, right? It's not tragic, but we might miss some information about other failed tests. That is, when a user reports a failed test to us, remaining results might be handy for debugging.

E.g. a sound file that's exactly 1 second long and contains a specific set of data.
Maybe a more general question: how do we operationally test such multimedia features? We can of course access the raw data (audio samples, pixels, ...) to some extent.

But, do we check whether a resource has been loaded correctly, for example? Or test rendering... are there some state-of-the art techniques, or should we just sample some pixels and compare with hardcoded values? ;)

Anyway, I think there are enough other things to test before we get to this point, so it's not a blocking issue 8)
Title: Re: Unit tests
Post by: Hiura on April 28, 2015, 09:28:42 pm
No answer here, just more questions: How de we make sure the window is properly positioned, that an event is generated when the user clicks on his mouse, that the title is correct, ...

We probably don't have to go as far as testing the title but making sure the same events are generated oj all OSes could be good. Bu how?...
Title: Re: Unit tests
Post by: Nexus on April 28, 2015, 10:42:22 pm
Hiura, if there's something we cannot meaningfully hardcode in the C++ source (like a collection of events or so), one possibility is also to store them in a text file, and let the test read this file on different OSes. But I agree that such things will be very difficult to test, especially since you can't easily simulate user input.

I added string conversions for the following classes. I tried to make the format rather concise while still being expressive enough.
Keep in mind that it only makes sense to provide string conversions for types that support relational operators, or at least == and !=, as they're used in Catch assertion expressions. So don't start to write conversions for sf::Sprite or so.

Types that are still missing are all the enums, like mouse buttons, joystick axes, keyboard keys, event types, and so on. But enums are a pain to serialize in C++, as you can essentially perform a case differentiation for every single enumerator. I did this in Thor (https://github.com/Bromeon/Thor/blob/master/src/InputNames.cpp) for some of them... But I think here I'll wait until we actually need them, otherwise we just have to keep it in sync with the original enums (<- this maintenance is the problem).

Furthermore, I introduced a new header UnitTests.hpp which is used by all the test cases. It indirectly includes <catch.hpp>. Don't include <catch.hpp> directly, or else you will not benefit from string conversions.

I also added tags in TEST_CASE.

Any opinions on these changes? What do you think about the enums?
Title: Re: Unit tests
Post by: Tank on April 29, 2015, 08:28:36 am
Good stuff. :) Regarding the enums: We can do it for things like EventType, for example, where it might be useful. But for enums like sf::Keyboard::Key I wouldn't really do it.
Title: Re: Unit tests
Post by: Tank on April 29, 2015, 08:34:28 am
And regarding to what Hiura said:
This is currently not really testable, because SFML hasn't been developed with being easily testable in mind (in contrast to doing test-driven development, for example). What you usually do is using mock objects.

Instead of querying the actual OS for events, for example, or the mouse position, you use a mock object that has the same interface, but is controllable by the unit test. That way you can manually set a mouse position that the unit to be tested retrieves, and thus you can test if it functions properly. The same applies to nearly anything that requires external dependencies.
Title: Re: Unit tests
Post by: Hiura on April 29, 2015, 08:50:40 am
That 'mock' strategy should probably be taken into account for SFML 3, don't you think?
Title: Re: Unit tests
Post by: Tank on April 29, 2015, 09:37:24 am
Yeah.
Title: Re: Unit tests
Post by: Nexus on April 29, 2015, 12:56:35 pm
Wouldn't that require a massive internal rewrite? An additional intermediate abstraction layer just for mocking would increase the complexity and with it the maintenance effort for all times. And don't forget that some operations have to be fast, we can't just add a virtual function call in every SFML operation ;)

Considering that most event- and input-related bugs appear because of different behavior of all the platform-specific APIs and not because of mistakes in SFML's front-end, I'm not even sure how much mocking would help.
Title: Re: Unit tests
Post by: Hiura on April 29, 2015, 01:01:48 pm
By "taken into account" I didn't mean "implemented for everything".  ;)

Sure, some things might not be well suited for such testing, but some do. Now, I'm not experienced enough with TDD to tell off the top of my head which part could benefit from that. Maybe some of you have more intuition about that?
Title: Re: Unit tests
Post by: Tank on April 29, 2015, 01:27:43 pm
@Nexus:

Yeah, that requires a massive rewrite. Improving the whole codebase step-by-step is alright though. It's not that you have to do it all at once.

Automated tests for some areas are for sure very difficult to do, like rendered stuff etc. that behaves differently on different hardware.

Your concerns about slowing down certain areas are of course also valid. That's why you sometimes have to apply tricks and hacks to be able to exchange external dependencies. Unfortunately this can be very tough with both C++ and C, because things like overwriting symbols from outside is not possible. That pretty much leaves you with techniques like swapping external libraries with a mock replacement, or adding preprocessor directives to the internal code that allows to hook in mocking services.

100% test coverage should be the ultimate goal. We'll see what problems we'll encounter and what options exist to eliminate them. :)

@Hiura:

I didn't understand your question. :(
Title: Re: Unit tests
Post by: Hiura on April 29, 2015, 07:06:54 pm
@Tank: I'm just wondering if some of us -- probably you in fact -- have more experience with techniques involving mock objects and could help defining a good strategy for tests.

I did some TDD a few years back for some Android app (a class project) but tbh I didn't like it. Although it was most probably because we were not properly taught how to do it.
Title: Re: Unit tests
Post by: Tank on April 30, 2015, 01:58:29 pm
I've done some work on such things, yeah. Not much with C++, but I guess there are always ways. I could work something out I guess. Any idea for a concrete code location? Maybe window creation code or something?
Title: Re: Unit tests
Post by: eXpl0it3r on May 01, 2015, 03:36:11 pm
Now that my PC is currently building SFML including the unit test branch, I noticed an issue that I had as well back when working with FlexWorld.

If you build the unittest application with SFML linked shared and then try to run it, the unittest, won't know where the shared libraries are and will simply crash.
It's essentially useless when we allow running the test directly after building SFML shared.

Question is, do simply prevent the unittests from running with shared libraries or do we copy things around in the build directory so the sfmltest application will actually find the proper libraries?
Title: Re: Unit tests
Post by: Tank on May 04, 2015, 09:10:30 am
At least on Linux, the RPATH takes care of it, so that libraries don't have to be copied. Instead the full path to the libs is stored in the ELF file. I don't know how it works on Windows, though. If it's an issue, copying should work.

Quote from: eXpl0it3r
do simply prevent the unittests from running with shared libraries
That's simple indeed, but misses the point of unit testing. ;)
Title: Re: Unit tests
Post by: eXpl0it3r on October 10, 2015, 04:51:16 pm
So anyone willing to update the branch, address the issue of shared libraries and create a PR? ;)
Title: Re: Unit tests
Post by: eXpl0it3r on August 15, 2018, 11:22:26 pm
I just move this topic from internal discussions years ago into the public "SFML development" sub-forum, as the foundation for unit testing as discussed and implemented in this thread, will finally be merged in SFML 2.6.0.

See also the SFML Test Strategy (https://en.sfml-dev.org/forums/index.php?topic=24355.0) thread.