0

I have created an error object from an error hash and I'm trying to create unit tests that check the objects contain all the correct keys.

ErrorLibrary.pm

use constant {

    CABLING_ERROR => {
    errorCode => 561,
    message => "cabling is not correct at T1",
    tt => { template => 'disabled'},
    fatal => 1,
    link =>'http://www.e-solution.com/CABLING_ERROR',
    },
};

Error.pm - new subroutine. (Takes error hash as arg & creates a new error object)

package ASC::Builder:Error;
sub new {

    my ($package, $first_param) = (shift, shift);


    if (ref $first_param eq 'HASH') {
        my %params = @_;
        return bless { message => $first_param->{message}, %params}, $package;
    }
    else {
        my %params = @_; 
        return bless {message => $first_param, %params}, $package;

}   
}

I'm not sure what I should be testing as my expected output. The specific message key in the hash or an Error object itself. I've been trying to test if a certain key of the hash is contained in the error object, but I don't think I'm going about it the right way. Anyway here is what I've been messing around with:

error_test.t

my $error = CABLING_ERROR;
#is(ref $error, 'HASH', 'error is a hashref');


my $error_in = ASC::Builder::Error->new($error);

my $exp_out_A = ($error->{message}); # is this the right expected output????

is(ref $error_in eq ASC::Builder::Error, 'It is an Error object'); #seen something like this online

#is(defined $error->{errorCode}, 1, "Error object contains key errorCode"); #these only test that the error hash contains these keys
#is(defined $error->{message}, 1, "Error object contains key message");


is($error_in, $exp_out_A, 'Correct message output');

The test file is a bit messy, just because I've been trying various attempts. I hope all the code is free of syntax errors :). Any help would be much appreciated!

These are the other methods contained in the Error.pm file that I want to be able to access , the way I am accessing the error message from the hash. I am not sure if I they are correct, but I think they are pretty close.

    sub tt {
        my $self = shift;
        return $self->{tt} || {$_[0]->{tt} };
    }

sub code {
    my $self = shift;
    return $self->{code} || {$_[0]->{code} };
}

sub wiki_page {
    my $self = shift;
    return $self->{wiki_page} || {$_[0]->{wiki_page} };
}

The or condition in the return is suppose is so the error can be handled id its just a string or error hash.. I'm also not sure if this is correct.

When I run my unit test on for example the tt method I get the hash value returned instead of the value of tt which is 'disabled'.

Here is the unit test I ran on it:

my $error = CABLING_ERROR;

my $error_in = ASC::Builder::Error->new($error);

isa_ok($error_in, 'ASC::Builder::Error');

can_ok( $error_in, 'tt');
is($error_in->tt(), ( $error || $error->{tt} ), 'Returns correct template');
Paul Russell
  • 179
  • 10

1 Answers1

2

You're on the right track with your first test: new should return a valid object. But you should use isa_ok instead of checking the return of ref because isa_ok will also work with inheritance.

Change:

my $error_in = ASC::Builder::Error->new($error);
is(ref $error_in eq ASC::Builder::Error, 'It is an Error object');

to:

my $abe = ASC::Builder::Error->new($error); # less confusing variable name
isa_ok( $abe, 'ASC::Builder::Error' );

There's also new_ok, which is a shortcut:

my $abe = new_ok( ASC::Builder::Error => [ $error ] );

Your second test is a little off. $error_in is an object, but $exp_out_A is a string; it doesn't make sense to compare them.

You should write a method to get the error message string from your object:

# In package ASC::Builder::Error
sub message {
    return $_[0]->{message};
}

Now you should test that your object can call the message() method. You can do this with can_ok:

can_ok( $abe, 'message' );

Finally, you should test that the message() method returns the same message that you initialized your object with:

is( $abe->message(), $error->{message}, 'message() returns correct message' );
ThisSuitIsBlackNot
  • 23,492
  • 9
  • 63
  • 110
  • .This method works. But would you mind explaining what happens in the message subroutine. Does is just return the message key from whatever is passed into it as an argument? Thanks. – Paul Russell Mar 30 '16 at 19:04
  • 1
    Subroutine arguments are stored in the `@_` array and `$_[0]` is the first element of `@_`. When you call a method, the class name or object is automatically passed as the first argument. For example, when you call `$foo->bar('baz');`, `@_` contains `$foo` and `'baz'`. So `$_[0]->{message}` returns the value corresponding to the `message` key in the object. It would be clearer to write `my $self = shift; return $self->{message};` – ThisSuitIsBlackNot Mar 30 '16 at 19:14
  • I am trying to test the other values of the hash as well like code,tt and wiki_page, but the test returns hash references and not the actual values for each of the keys. How should I edit the methods for each of them in order to recognize the value? – Paul Russell Apr 01 '16 at 18:46
  • I don't quite understand what you're asking. Did you actually write methods for each of those attributes? – ThisSuitIsBlackNot Apr 01 '16 at 19:35
  • yes I did sorry , but I will include some of them in my question. I didn't realize they wern't included. – Paul Russell Apr 04 '16 at 13:58
  • Your edit should really be a new question, but `return $self->{tt} || {$_[0]->{tt} };` doesn't make sense. That returns the value of the `tt` attribute, unless the value is zero, the empty string, or something else that evaluates to false; in that case, it returns a hashref containing a single key (which will be either zero, the empty string, etc.), and a value of `undef`. – ThisSuitIsBlackNot Apr 04 '16 at 14:20
  • okay. Yeah I removed the or condition `$self->tt` and just `return { $_[0]->{tt} }` .. with tt it returns a hash ref.. When I apply the same return for the message method.. I get `undef` . I shall create a new question I suppose. Quite confused at the moment. – Paul Russell Apr 04 '16 at 14:31
  • Returning a hashref doesn't make sense either. The point of an accessor/getter method is to just get the value. So if you create an object `$foo` with a string attribute `myString`, `$foo->myString()` should return a string, not a hashref. Have you read [perlootut](http://perldoc.perl.org/perlootut.html)? If you're still confused after reading that, start a chat room and I'd be happy to explain a little more. – ThisSuitIsBlackNot Apr 04 '16 at 14:34
  • And I just realized that `tt` actually *is* a hashref in your code, so ignore my previous comment. Sorry if I confused you even more. All the other attributes you have are simple strings or numbers, so those methods should not be returning hashrefs. – ThisSuitIsBlackNot Apr 04 '16 at 15:01
  • Yeah I realized I had the mdeclared as hash refs. I have it working now. Thanks – Paul Russell Apr 04 '16 at 18:23