I'm using PHPUnit to auto-test my app. I want to assert the result of a function call which can return a boolean or a string. My code looks like this:
$myExample = new MyExample();
$value = $myExample->getValue();
if ($value !== false) {
assertNotNull($value);
assertFalse(empty($value));
}
But is it also possible to check whether the method executes successfully? Is "assertTrue($value)" the correct way?
UPDATE: Deprecated methods
Please use the following ones in case you want to check the data type:
assertIsArray()
assertIsBool()
assertIsFloat()
assertIsInt()
assertIsNumeric()
assertIsObject()
assertIsResource()
assertIsString()
assertIsScalar()
assertIsCallable()
assertIsIterable()
assertIsNotArray()
assertIsNotBool()
assertIsNotFloat()
assertIsNotInt()
assertIsNotNumeric()
assertIsNotObject()
assertIsNotResource()
assertIsNotString()
assertIsNotScalar()
assertIsNotCallable()
assertIsNotIterable()
UPDATE: As per mtiziani's comment below, this answer applies for PHPUnit versions below 9.#
If you want to assert the data type of the value, the correct way would be:
$this->assertInternalType('[expected_data_type]', $value);
The [expected_data_type] PHPUnit can validate can be any of these:
'array'
'boolean'
'bool'
'float'
'integer'
'int'
'null'
'numeric'
'object'
'resource'
'string'
'scalar'
'callable'
So, to assert that the returned value is a boolean, you would:
$this->assertInternalType('bool', $value);
You can use:
$this->assertSame($expect, $actual)
It will test for type and value (i.e. $expected===$actual).
If you want to test if the function returns false for certain data then you might consider doing that in a separate test method. The same with testing for a string. If you test for one value type at a time, the asserts are less complicated. Some people consider it to be good unit testing practice to have one assert per test method.
$this->assertFalse( $returnVal );
$this->assertInternalType('string', $returnValue);
Related
I have some code see EOM; it's by no means final but is the best way (so far) I've seen/conceived for validating multiple date formats in a somewhat performant way.
I'm wondering if there is a means to pass an additional argument to this kind of function (_normalise_coerce), it would be nice if the date format string could be defined in the schema. something like
{
"a_date":{
"type": "datetime",
"coerce": "to_datetime",
"coerce_args": "%m/%d/%Y %H:%M"
}
}
Vs making a code change in the function to support an additional date format. I've looked through the docs and not found anything striking. Fairly good chance I'm looking at this all wrong but figured asking the experts was the best approach. I think defining within the schema is the cleanest solution to the problem, but I'm all eyes and ears for facts, thoughts and opinions.
Some context:
Performance is essential as this could be running against millions of rows in AWS lambdas (and Cerbie (my nickname for cerberus) isn't exactly a spring chicken :P ).
None of the schemas will be native python dicts as they're all defined in JSON/YAML, so it all needs to be string friendly.
Not using the built-in coercion as the python types cannot be parsed from strings
I don't need the datetime object, so regex is a possibility, just less explicit and less futureproof.
If this is all wrong and I'm grossly incompetent, please be gentle (づ。◕‿‿◕。)づ
def _normalize_coerce_to_datetime(self, value: Union(str, datetime, None)) -> Union(datetime, str, None):
'''
Casts valid datetime strings to the datetime python type.
:param value: (str, datetime, None): python datetime, datetime string
:return: datetime, string, None. python datetime,
invalid datetime string or None if the value is empty or None
'''
datetime_formats = ['%m/%d/%Y %H:%M']
if isinstance(value, datetime):
return value
if value and not value.isspace():
for format in datetime_formats:
try:
return datetime.strptime(value, format)
except ValueError:
date_time = value
return date_time
else:
return None
I have attempted to do this myself and have not found a way to pass additional arguments to a custom normalize_coerce rule. If you want to extend the Cerberus library to include custom validators then you can include arguments and then access these through the constraints in the custom validator. The below is an example that I have used for a conditional to default coercer, but as I needed to specify the condition and both the value to check against and the value to return I couldn't find a way to do this with the normalize_coerce and hence applied inside a validate rule and edited the self.document, as seen by the code.
Schema:
{
"columns":{
"Customer ID":{
"type":"number",
"conditional_to_default":{
"condition":"greater_than",
"value_to_check_against":100,
"value_to_return":22
}
}
}
}
def _validate_conditional_to_default(self, constraint, field, value):
"""
Test the values and transform if conditions are met.
:param constraint: Dictionary with the args needed for the conditional check.
:param field: Field name.
:param value: Field value.
:return: the new document value if applicable, or keep the existing document value if not
"""
value_to_check_against = constraint["value_to_check_against"]
value_to_return = constraint["value_to_return"]
rule_name = 'conditional_to_default'
condition_mapping_dict = {"greater_than": operator.gt, "less_than": operator.lt, "equal_to": operator.eq,
"less_than_or_equal_to": operator.le,
"greater_than_or_equal_to": operator.ge}
if constraint["condition"] in condition_mapping_dict:
if condition_mapping_dict[constraint["condition"]](value, value_to_check_against):
self.document[field] = value_to_return
return self.document
else:
return self.document
if constraint["condition"] not in condition_mapping_dict:
custom_errors_list = []
custom_error = cerberus.errors.ValidationError(document_path=(field, ), schema_path=(field, rule_name),
code=0x03, rule=rule_name, constraint="Condition must be "
"one of: "
"{condition_vals}"
.format(condition_vals=list(condition_mapping_dict.keys())),
value=value, info=())
custom_errors_list.append(custom_error)
self._error(custom_errors_list)
return self.document
This is probably the wrong way to do it, but I hope the above gives you some inspiration and gets you a bit further. Equally I'm following this to see if anyone else has found a way to pass arguments to the _normlize_coerce function.
Map<String,bool> map= { "key1":true, "key2":false };
/*
* Flags following compilation error:
* A nullable expression can't be used as a condition.
* Try checking that the value isn't 'null' before using it as a condition.
*/
if(map["key1"]) {
//do sth
}
/*So I try checking value isn't null as specified in error
*Still flags same compilation error
*/
if(map!=null && map["key1"]) {
//do sth
}
//This works
if(map["key1"] == true) {
//do sth
}
}
Based on the following snippet, may I know why both the 1st and 2nd if blocks fail but not the 3rd?
You misunderstood the error message.
A nullable expression can't be used as a condition.
means that you can't do:
bool? condition;
if (condition) {
...
}
Map<K, V>'s operator[] returns a V?. It returns a nullable type as a way of indicating failure when the key isn't found, and you need to check that the returned value isn't null, not that map itself is not null. For example:
if (map["key"] ?? false) {
...
}
Your third approach (which checks == true) works because it will perform a null == true equality check if the lookup returns null. However, you should prefer using ?? false since it conveys the intent better, and equality checks against true or false are usually a code smell.
The [] operator on Map can return null which makes it nullable which is explained in details here: https://dart.dev/null-safety/understanding-null-safety#the-map-index-operator-is-nullable
So your first example is invalid since null is not a bool. So you cannot directly use the value from the [] operator for a Map.
Your second example is invalid for the same reason since map["key1"] is bool?.
Third example works since null == true is always false. So it is fully valid to make a comparison which involves something which can be null.
I am new to XQuery. Please guide me to solve the issue below I want to return the null value as a string, if the below expression does not give any value.
Currently, the output doesn't show the 'name' field itself. I want to have a name with null. for eg-
if (IsNull(expression),null,expression)
$output.dataAccessResponse[1]/*:row/*:name/text()
You could use the fn:exists() function to test whether or not there is a text() node.
exists($output.dataAccessResponse[1]/:row/:name/text())
You could also use the fn:boolean() function to test the effective boolean value of the node.
boolean($output.dataAccessResponse[1]/:row/:name/text())
If you wanted to test whether or not there was a significant value i.e. something other than whitespace, you can fn:normalize-space() in a predicate, to ensure that only text() nodes that have meaningful text are selected, and then test fn:exists().
exists($output.dataAccessResponse[1]/:row/:name/text()[normalize-space()])
XQuery doesn't have null, so if you are asking what to return to indicate null, then you would want to return an empty sequence () instead of null.
So, you could execute something like this:
let $name := $output.dataAccessResponse[1]/:row/:name/text()
return
if (fn:exists($name))
then $name
else ()
But at that point, it's really the same as just attempting to select the text() with that XPath and it will either return the text() node or an empty sequence:
$output.dataAccessResponse[1]/:row/:name/text()
I am using IDL 8.4. I want to use isa() function to determine input type read by read_csv(). I want to use /number, /integer, /float and /string as some field I want to make sure float, other to be integer and other I don't care. I can do like this, but it is not very readable to human eye.
str = read_csv(filename, header=inheader)
; TODO check header
if not isa(str.(0), /integer) then stop
if not isa(str.(1), /number) then stop
if not isa(str.(2), /float) then stop
I am hoping I can do something like
expected_header = ['id', 'x', 'val']
expected_type = ['/integer', '/number', '/float']
str = read_csv(filename, header=inheader)
if not array_equal(strlowcase(inheader), expected_header) then stop
for i=0l,n_elements(expected_type) do
if not isa(str.(i), expected_type[i]) then stop
endfor
the above doesn't work, as '/integer' is taken literally and I guess isa() is looking for named structure. How can you do something similar?
Ideally I want to pick expected type based on header read from file, so that script still works as long as header specifies expected field.
EDIT:
my tentative solution is to write a wrapper for ISA(). Not very pretty, but does what I wanted... if there is cleaner solution , please let me know.
Also, read_csv is defined to return only one of long, long64, double and string, so I could write function to test with this limitation. but I just wanted to make it to work in general so that I can reuse them for other similar cases.
function isa_generic,var,typ
; calls isa() http://www.exelisvis.com/docs/ISA.html with keyword
; if 'n', test /number
; if 'i', test /integer
; if 'f', test /float
; if 's', test /string
if typ eq 'n' then return, isa(var, /number)
if typ eq 'i' then then return, isa(var, /integer)
if typ eq 'f' then then return, isa(var, /float)
if typ eq 's' then then return, isa(var, /string)
print, 'unexpected typename: ', typ
stop
end
IDL has some limited reflection abilities, which will do exactly what you want:
expected_types = ['integer', 'number', 'float']
expected_header = ['id', 'x', 'val']
str = read_csv(filename, header=inheader)
if ~array_equal(strlowcase(inheader), expected_header) then stop
foreach type, expected_types, index do begin
if ~isa(str.(index), _extra=create_struct(type, 1)) then stop
endforeach
It's debatable if this is really "easier to read" in your case, since there are only three cases to test. If there were 500 cases, it would be a lot cleaner than writing 500 slightly different lines.
This snipped used some rather esoteric IDL features, so let me explain what's happening a bit:
expected_types is just a list of (string) keyword names in the order they should be used.
The foreach part iterates over expected_types, putting the keyword string into the type variable and the iteration count into index.
This is equivalent to using for index = 0, n_elements(expected_types) - 1 do and then using expected_types[index] instead of type, but the foreach loop is easier to read IMHO. Reference here.
_extra is a special keyword that can pass a structure as if it were a set of keywords. Each of the structure's tags is interpreted as a keyword. Reference here.
The create_struct function takes one or more pairs of (string) tag names and (any type) values, then returns a structure with those tag names and values. Reference here.
Finally, I replaced not (bitwise not) with ~ (logical not). This step, like foreach vs for, is not necessary in this instance, but can avoid headache when debugging some types of code, where the distinction matters.
--
Reflective abilities like these can do an awful lot, and come in super handy. They're work-horses in other languages, but IDL programmers don't seem to use them as much. Here's a quick list of common reflective features I use in IDL, with links to the documentation for each:
create_struct - Create a structure from (string) tag names and values.
n_tags - Get the number of tags in a structure.
_extra, _strict_extra, and _ref_extra - Pass keywords by structure or reference.
call_function - Call a function by its (string) name.
call_procedure - Call a procedure by its (string) name.
call_method - Call a method (of an object) by its (string) name.
execute - Run complete IDL commands stored in a string.
Note: Be very careful using the execute function. It will blindly execute any IDL statement you (or a user, file, web form, etc.) feed it. Never ever feed untrusted or web user input to the IDL execute function.
You can't access the keywords quite like that, but there is a typename parameter to ISA that might be useful. This is untested, but should work:
expected_header = ['id', 'x', 'val']
expected_type = ['int', 'long', 'float']
str = read_cv(filename, header=inheader)
if not array_equal(strlowcase(inheader), expected_header) then stop
for i = 0L, n_elemented(expected_type) - 1L do begin
if not isa(str.(i), expected_type[i]) then stop
endfor
I'd like to know how in C++/CLI it is possible to check whether an ArrayList is existent.
System::Collections::ArrayList %queue_tx
I tried if ( nullptr != queue_tx ) { queue_tx.Add(msg); } but that didn't work. I'm passing queue_tx as a parameter to a function and there's supposed to be the possibility of this parameter not being set (or being set to nullptr).
The compiler throws '!=' : no conversion from 'System::Collections::ArrayList' to 'nullptr'.
How do I do this?
% defines a reference variable this is why it cannot be null
if you would have declared the ArrayList like this:
System::Collections::ArrayList^ queue_tx
then your nullptr check would be possible and have a meaning
otherwise just use the queue_tx.Count() to check if the collection is empty
I would recommend going over:
the difference between reference and pointer variables
When to use a Reference VS Pointers
It is quite impossible for a T% to be null.