plumothy 0 Posted Monday at 09:50 AM I am new to unit testing and trying to understand how WillRaise works in DUnitX. In the simple example below, there is only 1 function being tested: it is given an integer it expects the given integer to be positive so raises EMySimpleException if it is zero or less otherwise, it just returns the given integer. The first two TestCases check the return value. One of them passes and one of them fails (which is correct). The next 2 TestCases use WillRaise to check if the correct exception is raised for a negative input. I expect one test to pass and one to fail - but they both pass and I don't understand why. I am assuming that I do not yet fully understand how to use WillRaise. Perhaps someone can point out my stupid error? The code being tested: unit MySimpleLogic; interface uses System.SysUtils; type EMySimpleException = class(Exception) public constructor Create(const Msg: string); overload; end; TMySimpleObject = class public function SimpleFunctionRequiringPositiveInput(const AValue: integer): integer; end; implementation { MySimpleObject } function TMySimpleObject.SimpleFunctionRequiringPositiveInput(const AValue: integer): integer; begin if (AValue <= 0) then raise EMySimpleException.Create('Negative input not allowed'); result := Avalue; end; { EMySimpleException } constructor EMySimpleException.Create(const Msg: string); begin inherited Create(Msg); end; end. The unit testing code: unit TestsForMySimpleLogic; interface uses System.SysUtils, DUnitX.TestFramework, MySimpleLogic; type [TestFixture] TMyTestObject = class private CUT: TMySimpleObject; public [Setup] procedure Setup; [TearDown] procedure TearDown; [Test] [TestCase('TestPositiveInput01','1,1')] [TestCase('TestPositiveInput02','1,2')] procedure TestPositiveInput(const AValue: integer; const Expected: integer); [Test] [TestCase('NegativeValueShouldRaiseEMySimpleException', '-1,EMySimpleException')] [TestCase('NegativeValueShouldRaiseESomeOtherException', '-2,ESomeOtherException')] procedure RaiseExceptionForNegativeInput(const AValue: integer; const exceptionClass : ExceptClass); end; implementation procedure TMyTestObject.TestPositiveInput(const AValue: integer; const Expected: integer); begin var Actual := CUT.SimpleFunctionRequiringPositiveInput(AValue); Assert.AreEqual(Expected, Actual); end; procedure TMyTestObject.RaiseExceptionForNegativeInput(const AValue: integer; const exceptionClass : ExceptClass); begin var TestMethod: TTestLocalMethod := procedure begin CUT.SimpleFunctionRequiringPositiveInput(AValue); end; Assert.WillRaise(TestMethod, exceptionClass, 'Incorrect Exception raised'); end; procedure TMyTestObject.Setup; begin CUT := TMySimpleObject.Create; end; procedure TMyTestObject.TearDown; begin CUT.Free; end; initialization TDUnitX.RegisterTestFixture(TMyTestObject); end. Share this post Link to post
Stefan Glienke 2009 Posted Monday at 12:42 PM (edited) Passing parameters like that does not work in DUnitX - it silently ignores the string name for the exception class and then passes nil. Calling Assert.WillRaise with nil as exceptionClass succeeds when any exception was raised. @Vincent Parrett should be able to tell the best way to pass any parameters that cannot be easily converted from string. Edited Monday at 12:45 PM by Stefan Glienke Share this post Link to post
plumothy 0 Posted Monday at 02:03 PM @Stefan Glienke OK, thank you, that explains my results. I looked at the comments for WillRaise: Quote Checks that an exception exactly matching ExceptClass will be raised Of course, I should have looked further than that! Share this post Link to post
Vincent Parrett 756 Posted Monday at 07:51 PM (edited) There is no special magic that will convert a string into an exception object in Delphi, you have to do that yourself. Test cases just create an array of TValue and attempt to pass those as args, using the rtl conversion functions to convert TValuue to the argument type. This really only works for strings and ordinal types, it won't construct an object for you. You could use a TTestDataProvider class, take a look at the ProviderExample unit in the examples folder. Edited Monday at 07:52 PM by Vincent Parrett Share this post Link to post
plumothy 0 Posted Monday at 10:13 PM @Vincent Parrett Will do - thank you. Share this post Link to post
plumothy 0 Posted yesterday at 08:13 AM The TTestDataProvider class looks like it will be very useful for me later. But, for now I have created a Helper for DUnitX.Assert which overrides WillRaise and takes the Exception as a string - here are the changes: : : type TDunitXAssertHelper = class helper for DUnitX.Assert class procedure WillRaise(AMethod: TTestLocalMethod; const ExceptionClass: string); overload; end; : : uses DUnitX.ResStrs; : : procedure TMyTestObject.RaiseExceptionForNegativeInput(const AValue: integer; const ExceptionClass : string); begin var TestMethod: TTestLocalMethod := procedure begin CUT.SimpleFunctionRequiringPositiveInput(AValue); end; Assert.WillRaise(TestMethod, exceptionClass); end; : : { TDunitXAssertHelper } class procedure TDunitXAssertHelper.WillRaise(AMethod: TTestLocalMethod; const ExceptionClass: string); begin DoAssert; try AMethod; except on E: Exception do begin Assert.AreEqual(ExceptionClass, E.ClassName ); exit; end; end; Fail(SNoException, ReturnAddress); end; Share this post Link to post