You're on the right track, but there are a couple things that need to change for this test to work.
Part of your problem right off the bat is that the mock that patch passes into your test method is called mockSocket, but your test code is referring to something called mock_socket.
Also, patch's first argument, the thing you want to patch, should be a string representation of the path to the module where you want to patch something. If your file structure looks like this:
|-- root_directory
| |
| |-- app_directory
| | |-- socketHandler.py
| | `-- somethingElse.py
| |
| `-- test_directory
| |-- testSocketHandler.py
| `-- testSomethingElse.py
and you run your tests from the root directory, you'd want to call patch like this: @mock.patch("app_directory.socketHandler.socket")
Constructor is called - The most important thing to realize is that mockSocket is a Mock object representing the socket class. So to test that the constructor was called, you need to check mockSocket.assert_called_with(...). That will pass if your production calls socket(...).
You may also want to assert that mySocketHandler.socket is the same object as mockSocket.return_value, to test that mySocketHandler not only calls the constructor, but assigns it to the right attribute.
and 3. connect and sendall are called properly - You should never call your mock in a test, because it can lead to falsely-passing assertions. In other words, you want your production code to be the only thing calling mocks. This means you shouldn't use the line new_sock = mock_socket(), because then your previous assertion about the constructor will pass no matter what your production code does, and I think it's causing your other assertions to fail.
mockSocketis already an instance of Mock, so it's return value will automatically be another, different Mock instance. Therefore, you don't need the first 2 lines of your test code above, and you only need one of the assertions on connect. The same ideas apply to sendall.
That's a lot to take in, here's what your test would look like if I wrote it:
from unittest import mock, TestCase
import pytest
import socketHandler
class TestSocketHandler(TestCase):
@mock.patch("app_directory.socketHandler.socket")
def test_socket_handler(mockSocketClass): # renamed this variable to clarify that it's a mock of a class.
# mockSocketClass is already a mock, so we can call production right away.
mySocketHandler = SocketHandler(...)
# Constructor of mockSocketClass was called
mockSocketClass.assert_called_with(...)
# Instance of mockSocketClass was assigned to correct attribute on SocketHandler
self.assertIs(mockSocketClass.return_value, mySocketHandler.socket)
# Production called connect on the return_value of the mock module, i.e. the instance of socket.
mockSocketClass.return_value.connect.assert_called_with(...)
# If SocketHandler's constructor calls sendall:
mockSocketClass.return_value.sendall.assert_called_with(expectedMessage)
Bonus Round! MagicMocks behave like Mocks, except that they implement some default values for some magic methods. I don't use them unless I absolutely need them. Here's an example:
from mock import Mock, MagicMock
mock = Mock()
magic_mock = MagicMock()
int(mock)
>>>Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: int() argument must be a string or a number, not 'Mock'
len(mock)
>>>Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'Mock' has no len()
int(magic_mock)
>>> 1
len(magic_mock)
>>> 0