3

I have been teaching myself how to code for about a year (I'm 17) and one of the most common things that I've come across while reading articles about programming is automated tests for your code.

I know automated testing is something very helpful but I still don't get it, what are you supposed to test in your code?

I've seen most of the tutorials on writing unit tests use assert_equal (in Python) to test two values.

Now for example I have this project which is somewhat a calculator, how am I supposed to write tests for the trigonometry part?

Is this the correct way of testing the script?

from src.trigonometry import calculate
def test_calculate():
    assert_equal(calculate("Degree", "Sin", 90), Math.sin(90 * Math.PI/180))
    # Similar assert_equals for other trig functions with angle 90

Another thing I am confused about is how am I supposed to write tests for scripts that interact with the web such as:

  • 2
    There are written a large number of books about this subject, so it is hard to cover testing in a single answer. But you are on the right track - you check if the function conforms to the specification by checking against known correct input and output. – JacquesB Jun 19 '16 at 10:42
  • As for unwieldy dependencies like the web, or databases, or other things like that, people tend to use Mocking to simplify their testing. See stackoverflow.com/a/2666006/569777 – MetaFight Jun 19 '16 at 10:58
  • Perhaps you can ask this in the Python section. People may be able to offer you some code snippets – John Kouraklis Jun 19 '16 at 16:48
  • This is really a question of good architecture. Rather than write a book, I'll refer you to Uncle Bob – RubberDuck Jun 19 '16 at 17:55
  • Side note: Avoid comparing floating-point numbers to expected results using exact comparison as it will make your tests very brittle. That is, unless you really mean to test for identity because of some deeper reasoning about the semantics of your code. – 5gon12eder Jun 19 '16 at 19:11
5

Is this the correct way of testing the script?

assert_equal(calculate("Degree", "Sin", 90), Math.sin(90 * Math.PI/180))

This tests if your function behaves identical to the standard library. Not if it behaves the way you expect it to behave. It is better to hardcode the expected result:

assert_equal(calculate("Degree", "Sin", 90), 1.0)

how am I supposed to write tests for scripts that interact with the web?

Unit tests should be as independent from other components as possible.

When you have your unit-test go online and do a network request, you are not just testing your code, but also your internet connection and the service you interact with. That's an integration test, not a unit test. The problem with such tests is that if they fail, you never know if it's your code which is to blame, your internet connection which doesn't work or an error in the service you interact with.

In a good unit test you minimize dependencies to other resources as much as possible. A common method for this are mock objects. A mock object is an object which looks and behaves identical to an object which abstracts an external resource (like a network connection or database connection object), but instead of actually doing a network request it just pretends to do one and returns a hardcoded result. This allows you to test if your code performs correctly without dependency on the 3rd party service.

In order to allow your unit tests to test your code with a mock network connection instead of a real one, you need to follow a development methodology called dependency injection. This methodology means that whenever an object has a dependency on a resource, it doesn't acquire that resource itself but instead gets that object handed to it from the outside. This allows your production code to supply a real network connection and your test code to supply a mock network connection.

The nice thing about mock network connections is that you can implement many different ones with different behaviors. This allows you to implement tests for your error handling in the case that the server does not behave as it usually does. You can, for example, test how your code behaves when the server suddenly closes the connection, responds with an error message or responds with total garbage.

| improve this answer | |
  • Thank you for such detailed explanation, helped a lot but now I have another small Q about unit tests, how many assert_equal tests am I supposed to make for a function? For instance in my above example I would call assert_equal on the basic angles (30, 45, 60, 90) as radians and degrees both but what if I had a simple function that would return the sum of two numbers, is just one assert_equal test sufficient? – Areeb Beigh Jun 20 '16 at 12:54
  • 1
    @AreebBeigh You would add tests for anything you imagine could go wrong. Also add tests for uncommon or improper use of the function. For example, how is your sinus calculation function supposed to behave on angles like -10, 365 or 4294967296? Or what if the first parameter is not "Degree"but "asdf", "" or 42? Then you add tests for anything that does go wrong during real-world usage of the program ("bugs") before you fix them. – Philipp Jun 20 '16 at 12:59
  • I see, so there is no "structured" convention to follow on such tests? – Areeb Beigh Jun 20 '16 at 13:00
  • @AreebBeigh There is no "structured" convention for what your functions do, so you can't have a "structured" convention on how to test them either. – Philipp Jun 20 '16 at 13:01
  • Alright, thanks for your help I've got some of this cleared now. Upvoted and accepted your answer. – Areeb Beigh Jun 20 '16 at 13:03
1

While not being a python developer, the tests shall be readable. Thus I'd suggest rewriting your test:

from src.trigonometry import calculate 
def test_calculate():

    expected = 0
    actual = calculate("Degree", "Sin", 90)

    assert_equal(expected, actual)
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.