In strongly typed languages such as Java, there is no need to explicitly check the type of object returned since the code cannot compile if the return types do not match method signature. Ex. You cannot return a boolean when an integer is expected.
In loosely typed languages such as Ruby, JavaScript, Python, etc., anything can be returned. Would it make sense to write a unit test that checks the type of object returned from a method? This, in my opinion, will ensure that a boolean is returned where a boolean is expected.
Is it even necessary to have the Unit test below?
=============================
An attempt at Ruby example:
first_module.rb:
module FirstModule
TypeA = Struct.new(
:prop1,
:prop2)
self.create_type_a
TypeA.new(
'prop1Val',
'prop2Val')
end
end
type_a_repository.rb:
module TypeARepository
def self.function_to_test
FirstModule.create_type_a # This will return TypeA object
end
end
type_a_repository_spec.rb:
RSpec.describe '' do
describe '' do
before do
allow(FirstModule).to receive(:create_type_a)
.and_return(FirstModule.create_type_a)
end
it '' do
result = TypeARepository.function_to_test
expect(result).to be_a(FirstModule::TypeA) # is this necessary?
end
end
end
The purpose of a unit test in software engineering is to verify the behavior of a relatively small piece of software, independently from other parts. Unit tests are narrow in scope, and allow us to cover all cases, ensuring that every single part works correctly.
Strongly typed means, a variable will not be automatically converted from one type to another. Weakly typed is the opposite: Perl can use a string like "123" in a numeric context, by automatically converting it into the int 123 . A strongly typed language like python will not do this.
A programming language is loosely typed, or weakly typed, when it does not require the explicit specification of different types of objects and variables. The "looser" typing rules in weakly typed programming languages can produce erroneous or unpredictable results. It can execute implicit type conversions at runtime.
Unit tests can be performed manually or automated. Those employing a manual method may have an instinctual document made detailing each step in the process; however, automated testing is the more common method to unit tests.
If you employ programming by contract then the answer's usually "no", as in so long as the return value meets expected criteria, which are often really loose, then you can't complain.
For example:
# Adds together zero or more integer values and returns the sum
def sum(*numbers)
numbers.inject(0,:+)
end
When testing you'd do something like this:
assert_equal 0, sum
assert_equal 1, sum(1)
assert_equal 0, sum(1, -1)
Now what happens when you supply non-integer values?
sum('1')
# => Exception: String can't be coerced into Integer
The original contract didn't specify that as a valid use case, so the exception is warranted. If you want to expand the scope:
# Adds together zero or more numerical values and returns the sum
def sum(*numbers)
numbers.map(&:to_i).inject(0,:+)
end
Now you can add together non-integer values:
assert_equal 6, sum(1, 2.0, '3')
Note that the whole time so long as the result passes the assert test you're satisfied. In Ruby 6.0
, 6
, and "6"
are all different, non-equivalent, so there's no worry about getting the wrong type.
This may not be true in other languages so you may need to be more specific about your results. The important thing is to avoid literal tests if you can, and instead just use the result as intended. For example:
assert_equal "this is amazing", "this is " + amazing_string_result
So long as whatever comes out of amazing_string_result
can be appended to a string and the result matches that's an acceptable response.
This often comes into play when you want literal true
or false
instead of some truthful value like 1
:
assert_true some_method?(:value)
Where if that returns a truthful but non-literal true
value the contract is broken and it fails.
Remember, there's an unlimited amount of paranoia you can have. Are you sure your values add up properly?
assert_equal 6, 1 + 2 + 3
assert_equal 6, 6
assert_equal 6, '6'.to_i
assert_true true
At some point you're no longer testing your code but are instead running regression tests on the programming language or hardware you're executing this code on, which is a complete waste of time if you're writing tests for your code.
The best unit tests:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With