1 2 Previous Next 18 Replies Latest reply on Apr 5, 2018 11:56 AM by user_78878863

    PSoC Creator 4.1 - including a .c file for unit testing

    ngerner001_3099001

      I'm trying to create a unit test .c file for each of my production code .c files, since I'd like the unit test functions to be in a separate .c file than my production code.  In order to do "white box" unit testing of my functions, I include the .c file I'm testing in the unit test file. 

      For example, in my fileToTest_unitTest.c file, I'd have

       

      #include "../src/fileToTest.c"

       

      The code compiles correctly, but I get a lot of linker errors saying that functions and variables have already been defined.  For example:

       

      .\CortexM0\ARM_GCC_541\Debug\fileToTest_unitTest.o: In function `GetCellSerialNum':

      fileToTest_unitTest.c:(.text.GetCellSerialNum+0x0): multiple definition of `GetCellSerialNum'

      .\CortexM0\ARM_GCC_541\Debug\fileToTest.o:fileToTest.c:(.text.GetCellSerialNum+0x0): first defined here

       

      How do I keep the linker happy in this case?

        • 1. Re: PSoC Creator 4.1 - including a .c file for unit testing
          user_24585443

          Hello,

           

          Can you post samples of one source file and one test file?

          This error just says you can't have the same functions (same name and parameters) in source files, because it is ambiguous, which of the functions should be called.

           

          David

          • 2. Re: PSoC Creator 4.1 - including a .c file for unit testing
            ngerner001_3099001

            Here is a watered-down example of what I'm trying to do.  In my unit tests, I should be able to manipulate variables that are defined in the .c file under test, and then call the functions that operate on them.  Please let me know if I'm overlooking something obvious.

            • 3. Re: PSoC Creator 4.1 - including a .c file for unit testing
              user_78878863

              Did you look at using one of the existing C unit testing / mocking frameworks (such as CUnit, CMoc, Ceedling)? Usually you separate the test from the regular code, and compile it in a separate step. That way they do no conflict with each other.

              Maybe look at this tutorial: https://dmitryfrank.com/articles/unit_testing_embedded_c_applications , I have used it already and it was quite easy. (Although not with PSoC, this was a different MCU)

              • 4. Re: PSoC Creator 4.1 - including a .c file for unit testing
                user_24585443

                I think this is the case.

                When the test files are removed from the project (and UNIT_TEST_ENABLED directive), the code compiles without any errors or warnings.

                 

                Anyway, it's a pity that there is not direct support for unit testing in PSoC Creator.

                • 5. Re: PSoC Creator 4.1 - including a .c file for unit testing
                  user_78878863

                  I'm not aware of any IDE that directly support unit (and mock) testing frameworks. Makefile-based IDEs have a slight advantage since you can influence the list of files that are compiled, so you can exclude your test code there while still having it in the IDE (and be able to edit it there).

                  • 6. Re: PSoC Creator 4.1 - including a .c file for unit testing
                    ngerner001_3099001

                    That is a really good tutorial on unit testing.  It looked like he was running his unit test from a host PC and not directly on the target though.  I'm trying to conditionally compile, to either have the target run its unit test or the application code. 

                     

                    The tutorial seems to demonstrate "black box" unit testing, where you only include header files, then pass parameters into the global functions, and check for the expected return values.  I was able to use this approach on some of my functions, and PSoC Creator didn't have any problems with those.

                     

                    The problem seems to occur when I want to #include the .c file under test, and set up some of its variables before calling my unit test function.  This is useful when unit testing a static function for example, and I don't want to compile the function as a global function.  This is more like "white box" unit testing, which allows me to unit test static functions without making them global solely for the purpose of unit testing.  I've researched online, and it seems like I *should* be able to get away with including a .c file at the top of my unit test file.  But including the .c file is the part that isn't working with the linker.    

                    • 7. Re: PSoC Creator 4.1 - including a .c file for unit testing
                      user_24585443

                      I don't know about any for embedded development either. On the other hand, things are moving slowly, but steadily. Top silicon manufacturers do not want to develop their own IDEs from scratch anymore, so we might get to a point, where a single instance of Eclipse or whatever will be used for many MCU families from different manufacturers. This would be a solid ground for one such integrated testing framework. All manufacturers and especially their customers would benefit from that.

                       

                      I haven't personally started doing unit testing, but I am looking around. However, I tested some important parts of code on PC (I mean x86 compiler), because it is a thousand times faster than on the target HW.

                       

                      For PCs, InteliJ IDEA and VIsual Studio, for example, support unit tests.

                      • 8. Re: PSoC Creator 4.1 - including a .c file for unit testing
                        user_78878863

                        First of all, unit testing, by definition, does not run on the real system. It does not matter whether we are talking about PC software or MCU code, when you do unit testing you test _one_ method in isolation. And isolation means not only other functions but also hardware. This is where the mocking part comes into play - it allows you to define mock version of the stuff that your function-under-test calls so you can control their return values (when needed).

                        Second: from my understanding _all_ functions in C are global. You expose them through their header files, but thats actually just convenience. So I don't understand your distinction between a 'static' and a 'global' function.

                        In your test, you include the header files for the functions you want to test. Then you setup the mocks (when you need some), then call your FUT.

                        Unit tests are normally not used to test functions that are not exposed as API in any form (in C, not being part of any header files). Why should you - the cannot be called by any other module anyway, so they cannot change observable behavior. Just test your API whether it does what it should.

                        • 9. Re: PSoC Creator 4.1 - including a .c file for unit testing
                          ngerner001_3099001

                          I'm not looking for feedback on my test approach, I'm looking for feedback on the linker error.  I should be able to run a unit test framework on my target platform if I choose to.  This test approach works successfully for the "black box" setup that I described.

                           

                          In c, I declare functions as static to ensure they can only be called from within the same c file, and they have local scope.  I'm fairly certain this is a common practice by developers.  I don't want to break that guideline just so that my local functions are unit-testable.  I've seen some people work around this be defining a macro for unit testing, but I was trying to avoid that.

                           

                          I welcome any other feedback or tips on how to include a .c file in another .c file for unit test purposes.

                           

                          #if UNIT_TEST
                          #define unit_static
                          #else
                          #define unit_static static
                          #endif

                          • 10. Re: PSoC Creator 4.1 - including a .c file for unit testing
                            user_78878863

                            As I said: normally you don't unit-test private (hidden) methods. You unit-test your module API (meaning the function exposed in the header files). These are the methods you need to care about, and make sure they behave correctly. Private methods will be tested by calling them from the public ones.

                            So you don't need to include the source code of your module into the test code.

                            • 11. Re: PSoC Creator 4.1 - including a .c file for unit testing
                              ngerner001_3099001

                              As I said: I'm not looking for feedback on my test approach, I'm looking for feedback on the linker error.  I can imagine cases where unit testing static functions directly would be useful.  For example, a thread with an incoming/outgoing message queue, which is it's only link to the rest of the world.  Within that thread, static functions 30 calls deep.  I'd have more confidence in my code if I could test each static function individually.

                               

                              I welcome any other feedback or tips on how to include a .c file in another .c file, and avoid linker problems when parent .c file calls functions from child .c file...

                              • 12. Re: PSoC Creator 4.1 - including a .c file for unit testing
                                user_78878863

                                #include-ing a source file into another essentially duplicates the code, so the linker is correct to complain about duplicated functions. Your only solution is to do the same as done with header files (which have the same problem): use #ifdef's.

                                Since the #include is done by the precompiler, the compiler and the linker just see two functions with the same name, and thats not allowed.

                                Either that or you re-structure your code to make it better testable (which, in my experience make the code better designed in most cases [but not all, I admit that]).

                                • 13. Re: PSoC Creator 4.1 - including a .c file for unit testing
                                  ngerner001_3099001

                                  I appreciate your insight on this problem.  I agree that this should work, and as part of my debugging before posting, I did try to add header guards to my .c file and it still didn't link properly.  I attached an updated version of my watered down example code with a header guard in the included .c file.  Still not sure why this simple example isn't linking properly. 

                                  1 of 1 people found this helpful
                                  • 14. Re: PSoC Creator 4.1 - including a .c file for unit testing
                                    user_78878863

                                    Using header guards will not solve the problem. They are designed for preventing _the same_ header file to be included _twice_ in the same source file (because then the compiler complains that function are redefined).

                                    But in your case, you need to make sure that the same function does not appear twice _in the whole source tree_. So you need to distinguish between regular compilation and compiling tests (assuming that each source file has exactly one test file).

                                    I think you can, somewhere in the build properties, configure that intermediate files are not deleted. Maybe its a GCC config. When you do so, you can inspect what the preprocessor is doing. Then look at the preprocessed files, and then think about what the compiler and the linker will do with the result.

                                    1 of 1 people found this helpful
                                    1 2 Previous Next