44using System ;
55using System . Collections . Generic ;
66using System . Linq ;
7+ using System . Net ;
8+ using System . Net . Sockets ;
79using System . Threading ;
810using Xunit ;
911
1012namespace XUnitTest ;
1113
12- /// <summary>ModbusSlave集成测试 - 覆盖更多场景 </summary>
13- public class ModbusSlaveIntegrationTests : IDisposable
14+ /// <summary>ModbusSlave集成测试的共享fixture,服务器仅启动一次 </summary>
15+ public class ModbusSlaveFixture : IDisposable
1416{
15- private readonly ModbusSlave _slave ;
16- private readonly Int32 _port ;
17+ public ModbusSlave Slave { get ; }
18+ public Int32 Port { get ; }
1719
18- public ModbusSlaveIntegrationTests ( )
20+ public ModbusSlaveFixture ( )
1921 {
20- _port = 1507 ;
21- _slave = new ModbusSlave
22+ // 使用OS分配的空闲端口,避免端口冲突
23+ var listener = new TcpListener ( IPAddress . Loopback , 0 ) ;
24+ listener . Start ( ) ;
25+ Port = ( ( IPEndPoint ) listener . LocalEndpoint ) . Port ;
26+ listener . Stop ( ) ;
27+
28+ Slave = new ModbusSlave
2229 {
23- Port = _port ,
30+ Port = Port ,
2431 Registers = Enumerable . Range ( 0 , 20 )
2532 . Select ( i => new RegisterUnit { Address = i , Value = ( UInt16 ) ( 200 + i ) } )
2633 . ToList ( ) ,
2734 Coils = Enumerable . Range ( 0 , 32 )
2835 . Select ( i => new CoilUnit { Address = i , Value = ( Byte ) ( i % 2 ) } )
2936 . ToList ( ) ,
3037 } ;
31- _slave . Start ( ) ;
38+ Slave . Start ( ) ;
3239 Thread . Sleep ( 200 ) ;
3340 }
3441
35- public void Dispose ( ) => _slave . Dispose ( ) ;
42+ public void Dispose ( ) => Slave . Dispose ( ) ;
43+ }
44+
45+ /// <summary>ModbusSlave集成测试 - 覆盖更多场景</summary>
46+ /// <remarks>
47+ /// 使用IClassFixture共享服务器实例,避免每个测试重复启动/停止。
48+ /// 读取初始值的测试使用寄存器0-9和线圈0-15(不被写测试修改);
49+ /// 写入测试使用寄存器10-19和线圈16-31(自包含,写后立即读回验证)。
50+ /// </remarks>
51+ public class ModbusSlaveIntegrationTests : IClassFixture < ModbusSlaveFixture >
52+ {
53+ private readonly ModbusSlaveFixture _fixture ;
54+
55+ public ModbusSlaveIntegrationTests ( ModbusSlaveFixture fixture )
56+ {
57+ _fixture = fixture ;
58+ }
3659
3760 private ModbusTcp CreateClient ( )
3861 {
3962 var client = new ModbusTcp
4063 {
41- Server = $ "tcp://localhost:{ _port } ",
64+ Server = $ "tcp://localhost:{ _fixture . Port } ",
4265 Timeout = 3000 ,
4366 } ;
4467 client . Open ( ) ;
4568 return client ;
4669 }
4770
48- #region 读取寄存器
71+ #region 读取寄存器(使用地址0-9,不被写测试修改)
4972 [ Fact ]
5073 public void ReadRegister_AllRegisters ( )
5174 {
5275 using var client = CreateClient ( ) ;
53- var rs = client . ReadRegister ( 1 , 0 , 20 ) ;
76+ var rs = client . ReadRegister ( 1 , 0 , 10 ) ;
5477 Assert . NotNull ( rs ) ;
55- Assert . Equal ( 20 , rs . Length ) ;
56- for ( var i = 0 ; i < 20 ; i ++ )
78+ Assert . Equal ( 10 , rs . Length ) ;
79+ for ( var i = 0 ; i < 10 ; i ++ )
5780 Assert . Equal ( ( UInt16 ) ( 200 + i ) , rs [ i ] ) ;
5881 }
5982
@@ -72,10 +95,10 @@ public void ReadRegister_MiddleRange()
7295 public void ReadRegister_LastRegister ( )
7396 {
7497 using var client = CreateClient ( ) ;
75- var rs = client . ReadRegister ( 1 , 19 , 1 ) ;
98+ var rs = client . ReadRegister ( 1 , 9 , 1 ) ;
7699 Assert . NotNull ( rs ) ;
77100 Assert . Single ( rs ) ;
78- Assert . Equal ( ( UInt16 ) 219 , rs [ 0 ] ) ;
101+ Assert . Equal ( ( UInt16 ) 209 , rs [ 0 ] ) ;
79102 }
80103
81104 [ Fact ]
@@ -89,15 +112,15 @@ public void ReadRegister_FirstRegister()
89112 }
90113 #endregion
91114
92- #region 读取线圈
115+ #region 读取线圈(使用地址0-15,不被写测试修改)
93116 [ Fact ]
94117 public void ReadCoil_AllCoils ( )
95118 {
96119 using var client = CreateClient ( ) ;
97- var rs = client . ReadCoil ( 1 , 0 , 32 ) ;
120+ var rs = client . ReadCoil ( 1 , 0 , 16 ) ;
98121 Assert . NotNull ( rs ) ;
99- Assert . Equal ( 32 , rs . Length ) ;
100- for ( var i = 0 ; i < 32 ; i ++ )
122+ Assert . Equal ( 16 , rs . Length ) ;
123+ for ( var i = 0 ; i < 16 ; i ++ )
101124 Assert . Equal ( i % 2 == 1 , rs [ i ] ) ;
102125 }
103126
@@ -143,37 +166,37 @@ public void ReadCoil_PartialByte()
143166 }
144167 #endregion
145168
146- #region 写入寄存器
169+ #region 写入寄存器(使用地址10-19,自包含写后读回)
147170 [ Fact ]
148171 public void WriteRegister_ThenRead ( )
149172 {
150173 using var client = CreateClient ( ) ;
151- var rs = client . WriteRegister ( 1 , 0 , 0x9999 ) ;
174+ var rs = client . WriteRegister ( 1 , 10 , 0x9999 ) ;
152175 Assert . Equal ( 0x9999 , rs ) ;
153176
154- var regs = client . ReadRegister ( 1 , 0 , 1 ) ;
177+ var regs = client . ReadRegister ( 1 , 10 , 1 ) ;
155178 Assert . Equal ( 0x9999 , regs [ 0 ] ) ;
156179 }
157180
158181 [ Fact ]
159182 public void WriteRegister_MaxValue ( )
160183 {
161184 using var client = CreateClient ( ) ;
162- var rs = client . WriteRegister ( 1 , 1 , 0xFFFF ) ;
185+ var rs = client . WriteRegister ( 1 , 11 , 0xFFFF ) ;
163186 Assert . Equal ( 0xFFFF , rs ) ;
164187
165- var regs = client . ReadRegister ( 1 , 1 , 1 ) ;
188+ var regs = client . ReadRegister ( 1 , 11 , 1 ) ;
166189 Assert . Equal ( 0xFFFF , regs [ 0 ] ) ;
167190 }
168191
169192 [ Fact ]
170193 public void WriteRegister_ZeroValue ( )
171194 {
172195 using var client = CreateClient ( ) ;
173- var rs = client . WriteRegister ( 1 , 2 , 0x0000 ) ;
196+ var rs = client . WriteRegister ( 1 , 12 , 0x0000 ) ;
174197 Assert . Equal ( 0 , rs ) ;
175198
176- var regs = client . ReadRegister ( 1 , 2 , 1 ) ;
199+ var regs = client . ReadRegister ( 1 , 12 , 1 ) ;
177200 Assert . Equal ( 0 , regs [ 0 ] ) ;
178201 }
179202
@@ -182,10 +205,10 @@ public void WriteRegisters_ThenRead()
182205 {
183206 using var client = CreateClient ( ) ;
184207 var values = new UInt16 [ ] { 0xAAAA , 0xBBBB , 0xCCCC , 0xDDDD } ;
185- var rs = client . WriteRegisters ( 1 , 10 , values ) ;
208+ var rs = client . WriteRegisters ( 1 , 13 , values ) ;
186209 Assert . Equal ( 4 , rs ) ;
187210
188- var regs = client . ReadRegister ( 1 , 10 , 4 ) ;
211+ var regs = client . ReadRegister ( 1 , 13 , 4 ) ;
189212 Assert . Equal ( 0xAAAA , regs [ 0 ] ) ;
190213 Assert . Equal ( 0xBBBB , regs [ 1 ] ) ;
191214 Assert . Equal ( 0xCCCC , regs [ 2 ] ) ;
@@ -196,27 +219,27 @@ public void WriteRegisters_ThenRead()
196219 public void WriteRegisters_SingleValue ( )
197220 {
198221 using var client = CreateClient ( ) ;
199- var rs = client . WriteRegisters ( 1 , 15 , new UInt16 [ ] { 0x1111 } ) ;
222+ var rs = client . WriteRegisters ( 1 , 17 , new UInt16 [ ] { 0x1111 } ) ;
200223 Assert . Equal ( 1 , rs ) ;
201224
202- var regs = client . ReadRegister ( 1 , 15 , 1 ) ;
225+ var regs = client . ReadRegister ( 1 , 17 , 1 ) ;
203226 Assert . Equal ( 0x1111 , regs [ 0 ] ) ;
204227 }
205228 #endregion
206229
207- #region 写入线圈
230+ #region 写入线圈(使用地址16-31,自包含写后读回)
208231 [ Fact ]
209232 public void WriteCoil_ThenRead ( )
210233 {
211234 using var client = CreateClient ( ) ;
212- // 线圈0初始为0,写入1
213- client . WriteCoil ( 1 , 0 , 0xFF00 ) ;
214- var rs = client . ReadCoil ( 1 , 0 , 1 ) ;
235+ // 写入ON
236+ client . WriteCoil ( 1 , 16 , 0xFF00 ) ;
237+ var rs = client . ReadCoil ( 1 , 16 , 1 ) ;
215238 Assert . True ( rs [ 0 ] ) ;
216239
217240 // 再关闭
218- client . WriteCoil ( 1 , 0 , 0x0000 ) ;
219- rs = client . ReadCoil ( 1 , 0 , 1 ) ;
241+ client . WriteCoil ( 1 , 16 , 0x0000 ) ;
242+ rs = client . ReadCoil ( 1 , 16 , 1 ) ;
220243 Assert . False ( rs [ 0 ] ) ;
221244 }
222245
@@ -226,10 +249,10 @@ public void WriteCoils_ThenRead()
226249 using var client = CreateClient ( ) ;
227250 // 写入8个线圈:全开
228251 var values = new UInt16 [ ] { 0xFF00 , 0xFF00 , 0xFF00 , 0xFF00 , 0xFF00 , 0xFF00 , 0xFF00 , 0xFF00 } ;
229- var rs = client . WriteCoils ( 1 , 0 , values ) ;
252+ var rs = client . WriteCoils ( 1 , 16 , values ) ;
230253 Assert . Equal ( 8 , rs ) ;
231254
232- var coils = client . ReadCoil ( 1 , 0 , 8 ) ;
255+ var coils = client . ReadCoil ( 1 , 16 , 8 ) ;
233256 for ( var i = 0 ; i < 8 ; i ++ )
234257 Assert . True ( coils [ i ] ) ;
235258 }
@@ -240,10 +263,10 @@ public void WriteCoils_AllOff_ThenRead()
240263 using var client = CreateClient ( ) ;
241264 // 全关
242265 var values = new UInt16 [ ] { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
243- var rs = client . WriteCoils ( 1 , 0 , values ) ;
266+ var rs = client . WriteCoils ( 1 , 16 , values ) ;
244267 Assert . Equal ( 8 , rs ) ;
245268
246- var coils = client . ReadCoil ( 1 , 0 , 8 ) ;
269+ var coils = client . ReadCoil ( 1 , 16 , 8 ) ;
247270 for ( var i = 0 ; i < 8 ; i ++ )
248271 Assert . False ( coils [ i ] ) ;
249272 }
@@ -254,10 +277,10 @@ public void WriteCoils_NonMultipleOf8_ThenRead()
254277 using var client = CreateClient ( ) ;
255278 // 写5个线圈(非8的倍数)
256279 var values = new UInt16 [ ] { 0xFF00 , 0x0000 , 0xFF00 , 0x0000 , 0xFF00 } ;
257- var rs = client . WriteCoils ( 1 , 16 , values ) ;
280+ var rs = client . WriteCoils ( 1 , 24 , values ) ;
258281 Assert . Equal ( 5 , rs ) ;
259282
260- var coils = client . ReadCoil ( 1 , 16 , 5 ) ;
283+ var coils = client . ReadCoil ( 1 , 24 , 5 ) ;
261284 Assert . True ( coils [ 0 ] ) ;
262285 Assert . False ( coils [ 1 ] ) ;
263286 Assert . True ( coils [ 2 ] ) ;
@@ -280,20 +303,20 @@ public void WriteCoils_Pattern_ThenRead()
280303 }
281304 #endregion
282305
283- #region 读写组合场景
306+ #region 读写组合场景(使用写区域地址,自包含)
284307 [ Fact ]
285308 public void ReadWrite_RegisterRoundTrip ( )
286309 {
287310 using var client = CreateClient ( ) ;
288311
289- // 写入一系列值,然后读回
312+ // 写入一系列值,然后读回(使用寄存器10-19)
290313 for ( UInt16 i = 0 ; i < 10 ; i ++ )
291314 {
292315 var val = ( UInt16 ) ( i * 1000 ) ;
293- client . WriteRegister ( 1 , i , val ) ;
316+ client . WriteRegister ( 1 , ( UInt16 ) ( 10 + i ) , val ) ;
294317 }
295318
296- var regs = client . ReadRegister ( 1 , 0 , 10 ) ;
319+ var regs = client . ReadRegister ( 1 , 10 , 10 ) ;
297320 for ( var i = 0 ; i < 10 ; i ++ )
298321 Assert . Equal ( ( UInt16 ) ( i * 1000 ) , regs [ i ] ) ;
299322 }
@@ -303,14 +326,14 @@ public void ReadWrite_CoilRoundTrip()
303326 {
304327 using var client = CreateClient ( ) ;
305328
306- // 逐个设置线圈
329+ // 逐个设置线圈(使用线圈24-31)
307330 for ( var i = 0 ; i < 8 ; i ++ )
308331 {
309332 var value = ( UInt16 ) ( i % 3 == 0 ? 0xFF00 : 0x0000 ) ;
310- client . WriteCoil ( 1 , ( UInt16 ) i , value ) ;
333+ client . WriteCoil ( 1 , ( UInt16 ) ( 24 + i ) , value ) ;
311334 }
312335
313- var coils = client . ReadCoil ( 1 , 0 , 8 ) ;
336+ var coils = client . ReadCoil ( 1 , 24 , 8 ) ;
314337 for ( var i = 0 ; i < 8 ; i ++ )
315338 Assert . Equal ( i % 3 == 0 , coils [ i ] ) ;
316339 }
@@ -341,8 +364,8 @@ public void Slave_DefaultPort()
341364 [ Fact ]
342365 public void Slave_RegistersAndCoils ( )
343366 {
344- Assert . Equal ( 20 , _slave . Registers . Count ) ;
345- Assert . Equal ( 32 , _slave . Coils . Count ) ;
367+ Assert . Equal ( 20 , _fixture . Slave . Registers . Count ) ;
368+ Assert . Equal ( 32 , _fixture . Slave . Coils . Count ) ;
346369 }
347370
348371 [ Fact ]
0 commit comments