3

In Java I can have a main function in every class and just use the one I want. This is often useful because I can put test routines in the main function run that class specifically to test it.

In C, however, no two functions can have the same prototype, so there can be only one main in the whole project. I can rename individual mains, but then I have to tediously edit the names to run the file of interest.

Is there any way around this, so I can have multiple mains, or is that just not going to happen?

Tyler Durden
  • 10,296
  • 8
  • 53
  • 109
  • Unrelated question, but is it standard and/or wise to test classes with its own `main()` method? I've just never heard of anyone doing that. – Zephyr Jan 18 '19 at 04:42
  • @Zephyr In Java, it is convenient because you just run that class, "java myclasstotest.class" so as long as you have a main in that class, it will run that particular main. So, for example, if you have a class with a bunch of utility functions, then the main in that class can run tests on the utility functions. – Tyler Durden Jan 18 '19 at 04:45
  • No, I definitely understand the convenience of it. I just don't know if having a public method like that in all my classes is a good idea. I like the idea; was just curious if it's a good practice. – Zephyr Jan 18 '19 at 04:49
  • 3
    @Zephyr - sounds like a lazy way out of not having proper unit tests – Scary Wombat Jan 18 '19 at 04:59
  • 1
    No, it is not good practice to write it like that. Your unit tests should always be in a separate test class, within the `test` package. If you do not do that, your test code will be packaged together with your source code (which is in the `main` package). That is bad. – Timothy T. Jan 18 '19 at 05:02
  • @ScaryWombat Some might say "lazy", others might say "efficient". – Tyler Durden Jan 18 '19 at 05:10
  • @TimothyT. Why is it bad to have test code in the same source file? Splitting them up creates a logistical problem. I find it very convenient and natural to have the test code in the same file. – Tyler Durden Jan 18 '19 at 05:11
  • Not so much "no two functions can have the same prototype" as "no two functions can have the same name" — ignoring `_Generic` which only disguises the fact there is a different name for each function. – Jonathan Leffler Jan 18 '19 at 05:14
  • `main()`, no matter language, is synonymous to the linked executable entry point. Neither in C nor Java should some random class/ADT have anything to do with that, because it is an application detail outside the purpose and task of that specific class/ADT. If it knows about main(), then that creates a tight coupling between non-related parts of the program, which is an entirely bad thing to have. Thus the solution is to not have a `main()` inside any other class than the one concerned with the entry point of the program alone. Everything else is poor design, no matter language. – Lundin Jan 18 '19 at 08:56
  • As for unit testing, it should be handled separately and not interfere with program design. Things like TDD with integrated tests in the design, adds dangerous clutter and bugs, when the test code accidentally starts executing during live application use. – Lundin Jan 18 '19 at 08:57

2 Answers2

3

Most of my C library code can be compiled with -DTEST to expose the main() (and often some auxilliary functions too) in the source file with the implementation. So if I have a set of functions declared in source.h and defined in source.c, then source.c might look like:

#include "source.h"
#include …other headers…

…code defining functions declared in source.h

#ifdef TEST

#include <stdio.h>

int main(void)
{
    …test code…
}

#endif /* TEST */

This works when the test suite is small enough to fit in the source file. If the tests get bigger than the code, then I create one or more separate source files containing test code. Each of those files can have its own main(), or they can be designed to be linked together — whichever seems more convenient.

What's appropriate depends on the size and complexity of the tests. Some functions end up with fixed — hard-wired — tests; some spend time reading data from standard input; others process argument lists if supplied and fall back on some minimal test if there are no arguments. The test code might use a unit test infrastructure or might be more or less ad hoc, again depending on complexity (and antiquity) of the code.

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
  • That's a great approach. Very simple and direct. – Tyler Durden Jan 18 '19 at 05:29
  • Note also the discussion and rules in [Should I use `#include` in headers](https://stackoverflow.com/questions/1804486/should-i-use-include-in-headers). The outline code above obeys the NASA GSFC rules by including `source.h` before any other headers, thus checking that the header can be used in isolation (by simply writing `#include "source.h"`) and all necessary declarations are provided; there are no other pre-requisite headers. This is a simple and valuable trick that helps ensure your code is (re)usable. – Jonathan Leffler Jan 18 '19 at 05:50
2

You can put the majority of your code into a shared library.

You would then have a source file with your "regular" main function that compiles to an executable by itself and uses the shared library. Then you can write a separate test program that also links in the library that can run the various tests needed.

dbush
  • 162,826
  • 18
  • 167
  • 209
  • Yes, I guess writing a separate test program is the natural way to do it, but of course, then I have two files for every body of functions, the main source and test file. – Tyler Durden Jan 18 '19 at 05:06