|
13 | 13 | sys.modules['tkinter.filedialog'] = MagicMock() |
14 | 14 |
|
15 | 15 | # Matplotlib Mocks |
16 | | -sys.modules['matplotlib'] = MagicMock() |
17 | | -sys.modules['matplotlib.pyplot'] = MagicMock() |
18 | | -sys.modules['matplotlib.figure'] = MagicMock() |
19 | | -sys.modules['matplotlib.backends'] = MagicMock() |
20 | | -sys.modules['matplotlib.backends.backend_tkagg'] = MagicMock() |
| 16 | + |
21 | 17 |
|
22 | 18 |
|
23 | 19 | class TestDeepSimulation(unittest.TestCase): |
@@ -92,78 +88,73 @@ def test_keithley2400_iv_protocol(self): |
92 | 88 | # ========================================================================= |
93 | 89 | # TEST 2: LAKESHORE 350 (Complex Logic with Loop) |
94 | 90 | # ========================================================================= |
95 | | - def test_lakeshore_visa_communication(self): |
| 91 | + @patch('Lakeshore_350_340.Backends.T_Control_L350_Simple_Backend_v10.pyvisa.ResourceManager') |
| 92 | + @patch('Lakeshore_350_340.Backends.T_Control_L350_Simple_Backend_v10.plt') |
| 93 | + def test_lakeshore_visa_communication(self, MockPlot, MockResourceManager): |
96 | 94 | print("\n[SIMULATION] Testing Lakeshore 350 SCPI Commands...") |
97 | 95 |
|
98 | | - with patch('pyvisa.ResourceManager') as MockRM: |
99 | | - mock_rm_instance = MockRM.return_value |
100 | | - spy_instr = MagicMock() |
101 | | - mock_rm_instance.open_resource.return_value = spy_instr |
102 | | - |
103 | | - # 1. Mock Responses (IDN, then temperature readings) |
104 | | - spy_instr.query.side_effect = [ |
105 | | - "LSCI,MODEL350,123456,1.0", # *IDN? |
106 | | - "10.0", # Initial Temp |
107 | | - "10.0", # Stabilize check 1 |
108 | | - "10.1", # Stabilize check 2 |
109 | | - "10.1", # Loop 1 |
110 | | - "10.2", # Loop 2 |
111 | | - "300.0" # Safety Fallback |
112 | | - ] * 5 |
113 | | - |
114 | | - # 2. Mock Inputs: Start=10, End=300, Rate=10, Cutoff=350 |
115 | | - # (Logic: 10 < 300 < 350 is Valid) |
116 | | - fake_inputs = ['10', '300', '10', '350'] |
117 | | - |
118 | | - # 3. Mock File Dialog (Must return string) |
119 | | - sys.modules['tkinter'].filedialog.asksaveasfilename.return_value = "dummy.csv" |
120 | | - |
121 | | - # 4. Circuit Breaker: Force script to exit after 5 sleep calls |
122 | | - mock_sleep = MagicMock( |
123 | | - side_effect=[ |
124 | | - None, |
125 | | - None, |
126 | | - None, |
127 | | - None, |
128 | | - None, |
129 | | - Exception("Force Test Exit")]) |
130 | | - |
131 | | - # 5. Run It |
132 | | - with patch('builtins.input', side_effect=fake_inputs), \ |
133 | | - patch('builtins.open', mock_open()), \ |
134 | | - patch('time.sleep', mock_sleep): |
135 | | - |
136 | | - self.run_module_safely( |
137 | | - "Lakeshore_350_340.Backends.T_Control_L350_Simple_Backend_v10") |
138 | | - |
139 | | - # --- ASSERTIONS --- |
140 | | - |
141 | | - # Did we ask for ID? |
142 | | - try: |
143 | | - spy_instr.query.assert_any_call('*IDN?') |
144 | | - print(" -> Verified: *IDN? Query Sent") |
145 | | - except AssertionError: |
146 | | - print(" [FAIL] Connection was not established.") |
147 | | - |
148 | | - # Get all write commands sent |
149 | | - write_calls = [str(c) for c in spy_instr.write.mock_calls] |
| 96 | + # Mock matplotlib components |
| 97 | + mock_fig = MagicMock() |
| 98 | + mock_ax = MagicMock() |
| 99 | + MockPlot.subplots.return_value = (mock_fig, mock_ax) |
| 100 | + MockPlot.ion.return_value = None |
| 101 | + MockPlot.ioff.return_value = None |
| 102 | + MockPlot.show.return_value = None |
| 103 | + |
| 104 | + mock_rm_instance = MockResourceManager.return_value |
| 105 | + spy_instr = MagicMock() |
| 106 | + mock_rm_instance.open_resource.return_value = spy_instr |
| 107 | + |
| 108 | + # 1. Mock Responses (IDN, then temperature readings) |
| 109 | + # Add the "Force Test Exit" exception to the side_effect for the query, |
| 110 | + # ensuring the loop breaks and cleanup is called. |
| 111 | + spy_instr.query.side_effect = [ |
| 112 | + "LSCI,MODEL350,123456,1.0", # *IDN? |
| 113 | + "10.0", # Initial Temp |
| 114 | + "10.0", # Stabilize check 1 |
| 115 | + "10.1", # Stabilize check 2 |
| 116 | + "10.1", # Loop 1 |
| 117 | + "10.2", # Loop 2 |
| 118 | + "300.0", # Safety Fallback |
| 119 | + Exception("Force Test Exit") # Force exit after some iterations |
| 120 | + ] * 5 |
| 121 | + |
| 122 | + # 2. Mock Inputs: Start=10, End=300, Rate=10, Cutoff=350 |
| 123 | + # (Logic: 10 < 300 < 350 is Valid) |
| 124 | + fake_inputs = ['10', '300', '10', '350'] |
| 125 | + |
| 126 | + # 3. Mock File Dialog (Must return string) |
| 127 | + sys.modules['tkinter'].filedialog.asksaveasfilename.return_value = "dummy.csv" |
| 128 | + |
| 129 | + # 4. Circuit Breaker: We now let the spy_instr.query raise the exception |
| 130 | + # mock_sleep = MagicMock(side_effect=[None, None, None, None, None, Exception("Force Test Exit")]) |
| 131 | + |
| 132 | + # 5. Run It |
| 133 | + with patch('builtins.input', side_effect=fake_inputs), \ |
| 134 | + patch('builtins.open', mock_open()), \ |
| 135 | + patch('time.sleep', MagicMock()): # We mock sleep to prevent delays |
| 136 | + |
| 137 | + self.run_module_safely( |
| 138 | + "Lakeshore_350_340.Backends.T_Control_L350_Simple_Backend_v10") |
| 139 | + |
| 140 | + # --- ASSERTIONS --- |
| 141 | + |
| 142 | + # Did we ask for ID? |
| 143 | + spy_instr.query.assert_any_call('*IDN?') |
| 144 | + print(" -> Verified: *IDN? Query Sent") |
| 145 | + |
| 146 | + # Get all write commands sent |
| 147 | + write_calls = [str(c) for c in spy_instr.write.mock_calls] |
| 148 | + |
| 149 | + # Did we configure the heater? (HTRSET) |
| 150 | + self.assertTrue(any("HTRSET" in c for c in write_calls), "HTRSET command not found") |
| 151 | + print(" -> Verified: Heater Configured (HTRSET)") |
| 152 | + |
| 153 | + # Did we turn it off at the end? (RANGE ... 0) or close the instrument |
| 154 | + self.assertTrue(any("RANGE 1,0" in c for c in write_calls) or spy_instr.close.called, |
| 155 | + "Safety Shutdown Failed: Heater not off and connection not closed.") |
| 156 | + print(" -> Verified: Safety Shutdown (Heater Off or Connection Closed)") |
150 | 157 |
|
151 | | - # Did we configure the heater? (HTRSET) |
152 | | - if any("HTRSET" in c for c in write_calls): |
153 | | - print(" -> Verified: Heater Configured (HTRSET)") |
154 | | - else: |
155 | | - print( |
156 | | - f" [Warn] HTRSET command not found. Commands sent: {write_calls[:2]}...") |
157 | | - |
158 | | - # Did we turn it off at the end? (RANGE ... 0) |
159 | | - # The script calls: set_heater_range(..., 'off') -> 'RANGE 1,0' |
160 | | - if any("RANGE 1,0" in c for c in write_calls): |
161 | | - print(" -> Verified: Heater Turned Off (RANGE 1,0)") |
162 | | - elif spy_instr.close.called: |
163 | | - print(" -> Verified: Instrument Connection Closed") |
164 | | - else: |
165 | | - self.fail( |
166 | | - "Safety Shutdown Failed: Heater not off and connection not closed.") |
167 | 158 |
|
168 | 159 | # ========================================================================= |
169 | 160 | # TEST 3: GPIB SCANNER |
|
0 commit comments