digitalmars.D - Hack to name unit tests?
- Robert Fraser (21/21) Nov 28 2007 I'm creating a Flectioned-based way to run unit tests individually
- Dan (11/21) Nov 28 2007 I would have recommended you approach Walter and his team (whomever they...
- Leandro Lucarella (15/37) Nov 28 2007 Maybe something like
- Robert Fraser (5/10) Nov 28 2007 Besides the naming, all that is possible right now, which is what my
- =?iso-8859-15?Q?Jari-Matti_M=E4kel=E4?= (5/21) Nov 29 2007 Yep, it's a bit difficult to prove the correctness with unittests becaus...
- Christopher Wright (29/55) Nov 28 2007 class Unittest (string _name, alias _dg) : IUnittest {
- Robert Fraser (3/68) Nov 28 2007 Thanks! That's a good idea, but I want something compatible with current...
- Christopher Wright (30/99) Nov 29 2007 You already have to modify the tests to insert the name, but you want
- Dan (11/115) Nov 29 2007 Eww... no. You guys are suggesting that code provability is useless in ...
-
Christopher Wright
(5/6)
Nov 29 2007
- Robert Fraser (5/127) Nov 29 2007 It's not a bad idea, especially for smaller algorithms, but from my
- Robert Fraser (2/106) Nov 29 2007 Heh; alright; that's what I was looking for! Thanks!
- Christopher Wright (4/110) Nov 29 2007 No worries. It's pretty much identical in principle to mocked methods in...
- Daniel Keep (15/126) Nov 29 2007 Wouldn't it be simpler to provide an exern method that unittests could
- Christopher Wright (8/138) Nov 29 2007 There are advantages to throwing an exception when registering the name:
- Daniel Keep (7/17) Nov 29 2007 How is an exception an advantage in that case? When you run the test,
- Christopher Wright (8/28) Nov 30 2007 Exactly, exactly! Precisely what I told Miss Chow. Tissue augmentation,
- Robert Fraser (5/36) Nov 30 2007 Check Don's post in this topic for a way to get test names w/o runnning
- Don Clugston (9/27) Nov 29 2007 I think this is possible, but tricky. If your unit test has a local vari...
- Robert Fraser (3/36) Nov 30 2007 OK; _that's_ what I was looking for, since the test doesn't need to be
- Don Clugston (18/54) Dec 01 2007 Unfortunately, templated class don't show up in the normal class list ac...
I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!
Nov 28 2007
Robert Fraser Wrote:I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.)I would have recommended you approach Walter and his team (whomever they may be nowadays) with the idea.Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... }I'd like to see: unittest testName { // rest of text } I'd then like to be able to specifically execute only specific unit test(s) so that for instance I can debug the relationship between my x and y modules without triggering off a test of the whole freakin' alphabet. I would then like an improvement of unittests so that one can do more than merely assert(). Complete self-examination code should be possible - which means being able to examine program flow and trace variables. This would ultimately lead to *being able to* generate proofs on the correctness of the code. Someone could then just write a library.
Nov 28 2007
Dan, el 28 de noviembre a las 18:20 me escribiste:Robert Fraser Wrote:Maybe something like unittest "test name" { // rest of the test } could be more flexible about naming =) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- You should've seen her face. It was the exact same look my father gave me when I told him I wanted to be a ventriloquist. -- George ConstanzaI'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.)I would have recommended you approach Walter and his team (whomever they may be nowadays) with the idea.Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... }I'd like to see: unittest testName { // rest of text }
Nov 28 2007
Dan wrote:I'd then like to be able to specifically execute only specific unit test(s) so that for instance I can debug the relationship between my x and y modules without triggering off a test of the whole freakin' alphabet.Besides the naming, all that is possible right now, which is what my tool is doing.I would then like an improvement of unittests so that one can do more than merely assert(). Complete self-examination code should be possible - which means being able to examine program flow and trace variables. This would ultimately lead to *being able to* generate proofs on the correctness of the code. Someone could then just write a library.Hmmm... that sounds a bit complex for an average tester. Might be a good idea in a pure-functional language, but I can't see it being much use in D.
Nov 28 2007
On Wed, 28 Nov 2007, Robert Fraser wrote:Dan wrote:Yep, it's a bit difficult to prove the correctness with unittests because of side effects. Also 100% test coverage won't mean it works perfectly. Hmm, what about unittest as an attribute / annotation for functions. This works pretty well in Java and is more flexible than the one in D.I'd then like to be able to specifically execute only specific unit test(s) so that for instance I can debug the relationship between my x and y modules without triggering off a test of the whole freakin' alphabet.Besides the naming, all that is possible right now, which is what my tool is doing.I would then like an improvement of unittests so that one can do more than merely assert(). Complete self-examination code should be possible - which means being able to examine program flow and trace variables. This would ultimately lead to *being able to* generate proofs on the correctness of the code. Someone could then just write a library.Hmmm... that sounds a bit complex for an average tester. Might be a good idea in a pure-functional language, but I can't see it being much use in D.
Nov 29 2007
Robert Fraser wrote:I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!class Unittest (string _name, alias _dg) : IUnittest { static string name = _name; static void delegate() test = _dg; } Usage: Unittest!("my test for wossname", { assert (false, "haven't gotten around to implementing this yet"); }); Not guaranteed to work. Another tactic would be something like: class UnittestManager { static void registerCurrentTest (string name) {} static void endTest (bool success) {} static bool performTest () {} } template Unittest (string _name, alias _dg) { unittest { UnittestManager.registerCurrentTest(_name); // This lets us skip the test if we're just trying // to find out what tests there are currently. if (UnittestManager.performTest) { scope(success) UnittestManager.endTest(true); scope(failure) UnittestManager.endTest(false); _dg(); } } } mixin Unittest!("my test name", { assert (false, "not yet implemented"); });
Nov 28 2007
Christopher Wright wrote:Robert Fraser wrote:Thanks! That's a good idea, but I want something compatible with current unittest {} declarations.I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!class Unittest (string _name, alias _dg) : IUnittest { static string name = _name; static void delegate() test = _dg; } Usage: Unittest!("my test for wossname", { assert (false, "haven't gotten around to implementing this yet"); }); Not guaranteed to work. Another tactic would be something like: class UnittestManager { static void registerCurrentTest (string name) {} static void endTest (bool success) {} static bool performTest () {} } template Unittest (string _name, alias _dg) { unittest { UnittestManager.registerCurrentTest(_name); // This lets us skip the test if we're just trying // to find out what tests there are currently. if (UnittestManager.performTest) { scope(success) UnittestManager.endTest(true); scope(failure) UnittestManager.endTest(false); _dg(); } } } mixin Unittest!("my test name", { assert (false, "not yet implemented"); });
Nov 28 2007
Robert Fraser wrote:Christopher Wright wrote:You already have to modify the tests to insert the name, but you want something that works as a decorator inside the unittest. Can your unittest runner do a try/catch on a unittest? Then you could have something like: void testName(string name) { if (collectingNames) throw new UnittestNameException(name); } struct NamedTest { Unittest test; string name; } ... void main () { NamedTest[] tests; collectingNames = true; foreach (test; getUnittests) { try { test(); } catch (UnittestNameException e) { tests ~= NamedTest(test, e.name); } } collectingNames = false; } unittest { testName("blargh"); assert (false, "still working on this"); }Robert Fraser wrote:Thanks! That's a good idea, but I want something compatible with current unittest {} declarations.I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!class Unittest (string _name, alias _dg) : IUnittest { static string name = _name; static void delegate() test = _dg; } Usage: Unittest!("my test for wossname", { assert (false, "haven't gotten around to implementing this yet"); }); Not guaranteed to work. Another tactic would be something like: class UnittestManager { static void registerCurrentTest (string name) {} static void endTest (bool success) {} static bool performTest () {} } template Unittest (string _name, alias _dg) { unittest { UnittestManager.registerCurrentTest(_name); // This lets us skip the test if we're just trying // to find out what tests there are currently. if (UnittestManager.performTest) { scope(success) UnittestManager.endTest(true); scope(failure) UnittestManager.endTest(false); _dg(); } } } mixin Unittest!("my test name", { assert (false, "not yet implemented"); });
Nov 29 2007
Christopher Wright Wrote:Robert Fraser wrote:Eww... no. You guys are suggesting that code provability is useless in D because it's "too complicated" and then go on to suggest it can be used as a heavily over-classed debug statement. unittest is currently used more or less as a place to put a barrage of random sample tests. I was suggesting (beyond the obvious improvement of naming and only executing select unittests) that we should be able to put hooks to a provability program here. The provability program would be a separate utility that would go through and show things like bit overflow potential in numbers, potential infinities or potential bad memory accesses. It would do these things by following variables throughout their lifetimes to show all the different values they could possibly be at each time they're used. Combined with contract programming (in/out and invariant) this kind of thing exposes code in a way that running it with test values simply can't. For example: In libc, in qsort(), there was a bug because: median = (low + high) >> 1; The problem here is that in a very large array, low + high will eventually be > MAX_INT. This kind of bug isn't detected by simply doing a dumb random test on an array of 10. You need to be aware of the full range of possible values and use inductive logic to predict the bug without testing every last case. Regards, DanChristopher Wright wrote:You already have to modify the tests to insert the name, but you want something that works as a decorator inside the unittest. Can your unittest runner do a try/catch on a unittest? Then you could have something like: void testName(string name) { if (collectingNames) throw new UnittestNameException(name); } struct NamedTest { Unittest test; string name; } ... void main () { NamedTest[] tests; collectingNames = true; foreach (test; getUnittests) { try { test(); } catch (UnittestNameException e) { tests ~= NamedTest(test, e.name); } } collectingNames = false; } unittest { testName("blargh"); assert (false, "still working on this"); }Robert Fraser wrote:Thanks! That's a good idea, but I want something compatible with current unittest {} declarations.I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!class Unittest (string _name, alias _dg) : IUnittest { static string name = _name; static void delegate() test = _dg; } Usage: Unittest!("my test for wossname", { assert (false, "haven't gotten around to implementing this yet"); }); Not guaranteed to work. Another tactic would be something like: class UnittestManager { static void registerCurrentTest (string name) {} static void endTest (bool success) {} static bool performTest () {} } template Unittest (string _name, alias _dg) { unittest { UnittestManager.registerCurrentTest(_name); // This lets us skip the test if we're just trying // to find out what tests there are currently. if (UnittestManager.performTest) { scope(success) UnittestManager.endTest(true); scope(failure) UnittestManager.endTest(false); _dg(); } } } mixin Unittest!("my test name", { assert (false, "not yet implemented"); });
Nov 29 2007
Dan wrote:Eww... no. You guys are suggesting that code provability is useless in D because it's "too complicated" and then go on to suggest it can be used as a heavily over-classed debug statement.<snip> I don't know what thread you meant to reply to. This is only about naming tests somehow, not about proving anything about test coverage. Or am I confused about something?
Nov 29 2007
Dan wrote:Christopher Wright Wrote:It's not a bad idea, especially for smaller algorithms, but from my experience, using Coverity on a ~18 million LOC Java project fixed about 10 bugs, while the unit tests were constantly auditing check-ins, and prevented me from checking in at least that many of my own.Robert Fraser wrote:Eww... no. You guys are suggesting that code provability is useless in D because it's "too complicated" and then go on to suggest it can be used as a heavily over-classed debug statement. unittest is currently used more or less as a place to put a barrage of random sample tests. I was suggesting (beyond the obvious improvement of naming and only executing select unittests) that we should be able to put hooks to a provability program here. The provability program would be a separate utility that would go through and show things like bit overflow potential in numbers, potential infinities or potential bad memory accesses. It would do these things by following variables throughout their lifetimes to show all the different values they could possibly be at each time they're used. Combined with contract programming (in/out and invariant) this kind of thing exposes code in a way that running it with test values simply can't. For example: In libc, in qsort(), there was a bug because: median = (low + high) >> 1; The problem here is that in a very large array, low + high will eventually be > MAX_INT. This kind of bug isn't detected by simply doing a dumb random test on an array of 10. You need to be aware of the full range of possible values and use inductive logic to predict the bug without testing every last case. Regards, DanChristopher Wright wrote:You already have to modify the tests to insert the name, but you want something that works as a decorator inside the unittest. Can your unittest runner do a try/catch on a unittest? Then you could have something like: void testName(string name) { if (collectingNames) throw new UnittestNameException(name); } struct NamedTest { Unittest test; string name; } ... void main () { NamedTest[] tests; collectingNames = true; foreach (test; getUnittests) { try { test(); } catch (UnittestNameException e) { tests ~= NamedTest(test, e.name); } } collectingNames = false; } unittest { testName("blargh"); assert (false, "still working on this"); }Robert Fraser wrote:Thanks! That's a good idea, but I want something compatible with current unittest {} declarations.I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!class Unittest (string _name, alias _dg) : IUnittest { static string name = _name; static void delegate() test = _dg; } Usage: Unittest!("my test for wossname", { assert (false, "haven't gotten around to implementing this yet"); }); Not guaranteed to work. Another tactic would be something like: class UnittestManager { static void registerCurrentTest (string name) {} static void endTest (bool success) {} static bool performTest () {} } template Unittest (string _name, alias _dg) { unittest { UnittestManager.registerCurrentTest(_name); // This lets us skip the test if we're just trying // to find out what tests there are currently. if (UnittestManager.performTest) { scope(success) UnittestManager.endTest(true); scope(failure) UnittestManager.endTest(false); _dg(); } } } mixin Unittest!("my test name", { assert (false, "not yet implemented"); });
Nov 29 2007
Christopher Wright wrote:Robert Fraser wrote:Heh; alright; that's what I was looking for! Thanks!Christopher Wright wrote:You already have to modify the tests to insert the name, but you want something that works as a decorator inside the unittest. Can your unittest runner do a try/catch on a unittest? Then you could have something like: void testName(string name) { if (collectingNames) throw new UnittestNameException(name); } struct NamedTest { Unittest test; string name; } ... void main () { NamedTest[] tests; collectingNames = true; foreach (test; getUnittests) { try { test(); } catch (UnittestNameException e) { tests ~= NamedTest(test, e.name); } } collectingNames = false; } unittest { testName("blargh"); assert (false, "still working on this"); }Robert Fraser wrote:Thanks! That's a good idea, but I want something compatible with current unittest {} declarations.I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!class Unittest (string _name, alias _dg) : IUnittest { static string name = _name; static void delegate() test = _dg; } Usage: Unittest!("my test for wossname", { assert (false, "haven't gotten around to implementing this yet"); }); Not guaranteed to work. Another tactic would be something like: class UnittestManager { static void registerCurrentTest (string name) {} static void endTest (bool success) {} static bool performTest () {} } template Unittest (string _name, alias _dg) { unittest { UnittestManager.registerCurrentTest(_name); // This lets us skip the test if we're just trying // to find out what tests there are currently. if (UnittestManager.performTest) { scope(success) UnittestManager.endTest(true); scope(failure) UnittestManager.endTest(false); _dg(); } } } mixin Unittest!("my test name", { assert (false, "not yet implemented"); });
Nov 29 2007
Robert Fraser wrote:Christopher Wright wrote:No worries. It's pretty much identical in principle to mocked methods in dmocks, except for using exceptions to pass the name around and abort the method.Robert Fraser wrote:Heh; alright; that's what I was looking for! Thanks!Christopher Wright wrote:You already have to modify the tests to insert the name, but you want something that works as a decorator inside the unittest. Can your unittest runner do a try/catch on a unittest? Then you could have something like: void testName(string name) { if (collectingNames) throw new UnittestNameException(name); } struct NamedTest { Unittest test; string name; } ... void main () { NamedTest[] tests; collectingNames = true; foreach (test; getUnittests) { try { test(); } catch (UnittestNameException e) { tests ~= NamedTest(test, e.name); } } collectingNames = false; } unittest { testName("blargh"); assert (false, "still working on this"); }Robert Fraser wrote:Thanks! That's a good idea, but I want something compatible with current unittest {} declarations.I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!class Unittest (string _name, alias _dg) : IUnittest { static string name = _name; static void delegate() test = _dg; } Usage: Unittest!("my test for wossname", { assert (false, "haven't gotten around to implementing this yet"); }); Not guaranteed to work. Another tactic would be something like: class UnittestManager { static void registerCurrentTest (string name) {} static void endTest (bool success) {} static bool performTest () {} } template Unittest (string _name, alias _dg) { unittest { UnittestManager.registerCurrentTest(_name); // This lets us skip the test if we're just trying // to find out what tests there are currently. if (UnittestManager.performTest) { scope(success) UnittestManager.endTest(true); scope(failure) UnittestManager.endTest(false); _dg(); } } } mixin Unittest!("my test name", { assert (false, "not yet implemented"); });
Nov 29 2007
Christopher Wright wrote:Robert Fraser wrote:Wouldn't it be simpler to provide an exern method that unittests could call into? extern(C) void testName(char[] name); unittest { testName("blargh"); assert(false, "too lazy to write a real unit test..."); } You then provide testName somewhere in your runner program. If you want to compile without the unittest frontend, just create a stub object file with this in it: extern(C) void testName(char[] name) {} Should be a hell of a lot faster than tossing exceptions willy-nilly. -- DanielChristopher Wright wrote:No worries. It's pretty much identical in principle to mocked methods in dmocks, except for using exceptions to pass the name around and abort the method.Robert Fraser wrote:Heh; alright; that's what I was looking for! Thanks!Christopher Wright wrote:You already have to modify the tests to insert the name, but you want something that works as a decorator inside the unittest. Can your unittest runner do a try/catch on a unittest? Then you could have something like: void testName(string name) { if (collectingNames) throw new UnittestNameException(name); } struct NamedTest { Unittest test; string name; } ... void main () { NamedTest[] tests; collectingNames = true; foreach (test; getUnittests) { try { test(); } catch (UnittestNameException e) { tests ~= NamedTest(test, e.name); } } collectingNames = false; } unittest { testName("blargh"); assert (false, "still working on this"); }Robert Fraser wrote:Thanks! That's a good idea, but I want something compatible with current unittest {} declarations.I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!class Unittest (string _name, alias _dg) : IUnittest { static string name = _name; static void delegate() test = _dg; } Usage: Unittest!("my test for wossname", { assert (false, "haven't gotten around to implementing this yet"); }); Not guaranteed to work. Another tactic would be something like: class UnittestManager { static void registerCurrentTest (string name) {} static void endTest (bool success) {} static bool performTest () {} } template Unittest (string _name, alias _dg) { unittest { UnittestManager.registerCurrentTest(_name); // This lets us skip the test if we're just trying // to find out what tests there are currently. if (UnittestManager.performTest) { scope(success) UnittestManager.endTest(true); scope(failure) UnittestManager.endTest(false); _dg(); } } } mixin Unittest!("my test name", { assert (false, "not yet implemented"); });
Nov 29 2007
Daniel Keep wrote:Christopher Wright wrote:There are advantages to throwing an exception when registering the name: unittest { testName("this is the test that doesn't end"); while (true) {} } I was thinking that AssertionErrors couldn't be caught, but that was an error on my part.Robert Fraser wrote:Wouldn't it be simpler to provide an exern method that unittests could call into? extern(C) void testName(char[] name); unittest { testName("blargh"); assert(false, "too lazy to write a real unit test..."); } You then provide testName somewhere in your runner program. If you want to compile without the unittest frontend, just create a stub object file with this in it: extern(C) void testName(char[] name) {} Should be a hell of a lot faster than tossing exceptions willy-nilly. -- DanielChristopher Wright wrote:No worries. It's pretty much identical in principle to mocked methods in dmocks, except for using exceptions to pass the name around and abort the method.Robert Fraser wrote:Heh; alright; that's what I was looking for! Thanks!Christopher Wright wrote:You already have to modify the tests to insert the name, but you want something that works as a decorator inside the unittest. Can your unittest runner do a try/catch on a unittest? Then you could have something like: void testName(string name) { if (collectingNames) throw new UnittestNameException(name); } struct NamedTest { Unittest test; string name; } ... void main () { NamedTest[] tests; collectingNames = true; foreach (test; getUnittests) { try { test(); } catch (UnittestNameException e) { tests ~= NamedTest(test, e.name); } } collectingNames = false; } unittest { testName("blargh"); assert (false, "still working on this"); }Robert Fraser wrote:Thanks! That's a good idea, but I want something compatible with current unittest {} declarations.I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... } Right now, I have the associations being done in the front-end I'm working on, that scans the code for comments in a particular format and associates those with the unit tests. However, that ties the unit test executor back-end to the code analysis front-end, so I was hoping there's a better way. Thanks!class Unittest (string _name, alias _dg) : IUnittest { static string name = _name; static void delegate() test = _dg; } Usage: Unittest!("my test for wossname", { assert (false, "haven't gotten around to implementing this yet"); }); Not guaranteed to work. Another tactic would be something like: class UnittestManager { static void registerCurrentTest (string name) {} static void endTest (bool success) {} static bool performTest () {} } template Unittest (string _name, alias _dg) { unittest { UnittestManager.registerCurrentTest(_name); // This lets us skip the test if we're just trying // to find out what tests there are currently. if (UnittestManager.performTest) { scope(success) UnittestManager.endTest(true); scope(failure) UnittestManager.endTest(false); _dg(); } } } mixin Unittest!("my test name", { assert (false, "not yet implemented"); });
Nov 29 2007
Christopher Wright wrote:... There are advantages to throwing an exception when registering the name: unittest { testName("this is the test that doesn't end"); while (true) {} } I was thinking that AssertionErrors couldn't be caught, but that was an error on my part.How is an exception an advantage in that case? When you run the test, it's still going to spinlock, no matter how you've obtained the name. If what you're trying to get at is that you can build a list of all the names without having to run the actual test itself, then yes, I can see that being an advantage. -- Daniel
Nov 29 2007
Daniel Keep wrote:Christopher Wright wrote:Exactly, exactly! Precisely what I told Miss Chow. Tissue augmentation, it's not a matter of twiddling bits. On a more serious note, tools like the XUnit test runners display a list of names without running the tests. That's convenient, I think. The NUnit gui takes about twenty seconds to find all the unit tests we have at work, and it takes two or three minutes to run the tests. If I want to check a single test, two or three minutes is a long time.... There are advantages to throwing an exception when registering the name: unittest { testName("this is the test that doesn't end"); while (true) {} } I was thinking that AssertionErrors couldn't be caught, but that was an error on my part.How is an exception an advantage in that case? When you run the test, it's still going to spinlock, no matter how you've obtained the name. If what you're trying to get at is that you can build a list of all the names without having to run the actual test itself, then yes, I can see that being an advantage.-- Daniel
Nov 30 2007
Christopher Wright wrote:Daniel Keep wrote:Check Don's post in this topic for a way to get test names w/o runnning them at all (and depending on them throwing the exception; that is, unnamed tests will still work correctly). I'm going to be implementing that... assuming I can get the free time & sleep required for that.Christopher Wright wrote:Exactly, exactly! Precisely what I told Miss Chow. Tissue augmentation, it's not a matter of twiddling bits. On a more serious note, tools like the XUnit test runners display a list of names without running the tests. That's convenient, I think. The NUnit gui takes about twenty seconds to find all the unit tests we have at work, and it takes two or three minutes to run the tests. If I want to check a single test, two or three minutes is a long time.... There are advantages to throwing an exception when registering the name: unittest { testName("this is the test that doesn't end"); while (true) {} } I was thinking that AssertionErrors couldn't be caught, but that was an error on my part.How is an exception an advantage in that case? When you run the test, it's still going to spinlock, no matter how you've obtained the name. If what you're trying to get at is that you can build a list of all the names without having to run the actual test itself, then yes, I can see that being an advantage.-- Daniel
Nov 30 2007
Robert Fraser wrote:I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... }I think this is possible, but tricky. If your unit test has a local variable, and you instantiate a template using that local variable as an alias parameter, the module and the number of the unit test gets included into the mangled name. This means that it's possible for code to know which unit test it is inside. By making the template a class, you could to walk the RTTI list and make a lookup table to associate test numbers with their names. If you can get the list of unittest numbers from flectioned, you can join it BUT... that's all pretty hairy. Maybe there's a less convoluted way of doing it.
Nov 29 2007
Don Clugston wrote:Robert Fraser wrote:OK; _that's_ what I was looking for, since the test doesn't need to be run that way... time to get hacking!I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... }I think this is possible, but tricky. If your unit test has a local variable, and you instantiate a template using that local variable as an alias parameter, the module and the number of the unit test gets included into the mangled name. This means that it's possible for code to know which unit test it is inside. By making the template a class, you could to walk the RTTI list and make a lookup table to associate test numbers with their names. If you can get the list of unittest numbers from flectioned, you can join it BUT... that's all pretty hairy. Maybe there's a less convoluted way of doing it.
Nov 30 2007
Robert Fraser wrote:Don Clugston wrote:Unfortunately, templated class don't show up in the normal class list accessable through moduleinit.d, so it's you'll need to use flectioned for that too. Here's the simplest example I came up with which displays the module and unit test number (taken from my now-defunct NameOf module -- hmmm, might be worth rescuscitating a couple of ideas from it; it's much easier now we have CTFE). It only works if you've defined a local variable to use as an alias, which is a bit annoying. --- template testname(alias F) { enum testname { ignore } } template TESTNAME(alias K) { typedef void function(testname!(K)) TESTNAME; } unittest { int foo; pragma(msg, TESTNAME!(foo).mangleof[3..$-13]); } ----------Robert Fraser wrote:OK; _that's_ what I was looking for, since the test doesn't need to be run that way... time to get hacking!I'm creating a Flectioned-based way to run unit tests individually (it'll be hooked into a front-end, so you can run test suites, repeat only failed tests after a code change, etc.) However, I have run into a problem: unit tests can't be named. Right now I have a signature system, but I was wondering if there's any hackish way to predictably insert a string into the generated object file in a way that users can name unittests. That is to say, given a function pointer, is there any way I can scan the code to see if a name has been given to the unit test, and if so extract that name at runtime? Ideally, it'd be as easy for the user as something like: unittest { assert(":testName:"); // Rest of test goes here... }I think this is possible, but tricky. If your unit test has a local variable, and you instantiate a template using that local variable as an alias parameter, the module and the number of the unit test gets included into the mangled name. This means that it's possible for code to know which unit test it is inside. By making the template a class, you could to walk the RTTI list and make a lookup table to associate test numbers with their names. If you can get the list of unittest numbers from flectioned, you can join it BUT... that's all pretty hairy. Maybe there's a less convoluted way of doing it.
Dec 01 2007