-
-
Notifications
You must be signed in to change notification settings - Fork 128
Expand file tree
/
Copy pathAutoMockTests.cs
More file actions
211 lines (171 loc) · 5.11 KB
/
Copy pathAutoMockTests.cs
File metadata and controls
211 lines (171 loc) · 5.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
using TUnit.Mocks;
using TUnit.Mocks.Arguments;
using TUnit.Mocks.Exceptions;
using TUnit.Mocks.Verification;
namespace TUnit.Mocks.Tests;
/// <summary>
/// Interfaces for auto-mock testing — a chain of interface return types.
/// </summary>
public interface IServiceA
{
IServiceB GetServiceB();
string GetName();
}
public interface IServiceB
{
IServiceC GetServiceC();
int GetValue();
}
public interface IServiceC
{
string GetDescription();
}
/// <summary>
/// Interface that returns another interface via async method.
/// </summary>
public interface IAsyncProvider
{
Task<IServiceB> GetServiceAsync();
}
/// <summary>
/// Circular reference: INodeA references INodeB, INodeB references INodeA.
/// </summary>
public interface INodeA
{
INodeB GetNext();
}
public interface INodeB
{
INodeA GetPrevious();
}
/// <summary>
/// US1 Integration Tests: Recursive/auto mocking — interface return types automatically
/// return functional mocks instead of null.
/// </summary>
public class AutoMockTests
{
[Test]
public async Task Interface_Return_Type_Auto_Mocked()
{
// Arrange
var mock = IServiceA.Mock();
// Act — no setup for GetServiceB, should auto-mock
var serviceB = mock.Object.GetServiceB();
// Assert — should NOT be null
await Assert.That(serviceB).IsNotNull();
}
[Test]
public async Task Auto_Mocked_Return_Is_Functional()
{
// Arrange
var mock = IServiceA.Mock();
// Act
var serviceB = mock.Object.GetServiceB();
var value = serviceB.GetValue();
// Assert — auto-mocked IServiceB returns default int (0)
await Assert.That(value).IsEqualTo(0);
}
[Test]
public async Task Same_Instance_On_Repeated_Calls()
{
// Arrange
var mock = IServiceA.Mock();
// Act
var serviceB1 = mock.Object.GetServiceB();
var serviceB2 = mock.Object.GetServiceB();
// Assert — same cached instance
await Assert.That(serviceB1).IsSameReferenceAs(serviceB2);
}
[Test]
public async Task Nested_Chain_A_To_B_To_C()
{
// Arrange
var mock = IServiceA.Mock();
// Act — navigate the chain: A → B → C
var serviceB = mock.Object.GetServiceB();
var serviceC = serviceB.GetServiceC();
// Assert — entire chain is auto-mocked
await Assert.That(serviceC).IsNotNull();
}
[Test]
public async Task Nested_Chain_Returns_Default_Values()
{
// Arrange
var mock = IServiceA.Mock();
// Act
var serviceC = mock.Object.GetServiceB().GetServiceC();
var description = serviceC.GetDescription();
// Assert — default for string
await Assert.That(description).IsEqualTo("");
}
[Test]
public async Task Auto_Mock_Configurable_Via_Mock_Get()
{
// Arrange
var mock = IServiceA.Mock();
// Trigger auto-mock creation and retrieve the wrapper
var serviceB = mock.Object.GetServiceB();
var autoMock = Mock.Get(serviceB);
autoMock.GetValue().Returns(42);
// Act
var value = serviceB.GetValue();
// Assert
await Assert.That(value).IsEqualTo(42);
}
[Test]
public void Strict_Mode_Does_Not_Auto_Mock()
{
// Arrange
var mock = IServiceA.Mock(MockBehavior.Strict);
mock.GetName().Returns("test");
// Act & Assert — strict mode throws for unconfigured method
Assert.Throws<MockStrictBehaviorException>(() =>
{
mock.Object.GetServiceB();
});
}
[Test]
public async Task Explicit_Setup_Overrides_Auto_Mock()
{
// Arrange
var mock = IServiceA.Mock();
var customServiceB = IServiceB.Mock();
customServiceB.GetValue().Returns(99);
mock.GetServiceB().Returns(customServiceB.Object);
// Act
var serviceB = mock.Object.GetServiceB();
var value = serviceB.GetValue();
// Assert — explicit setup takes priority over auto-mock
await Assert.That(value).IsEqualTo(99);
}
[Test]
public async Task Auto_Mock_With_Circular_References()
{
// Arrange
var mock = INodeA.Mock();
// Act — navigate circular reference
var nodeB = mock.Object.GetNext();
// Assert — auto-mocked, not null
await Assert.That(nodeB).IsNotNull();
}
[Test]
public async Task Async_Method_Returns_Auto_Mock()
{
// Arrange
var mock = IAsyncProvider.Mock();
// Act — async method returning Task<IServiceB>
var serviceB = await mock.Object.GetServiceAsync();
// Assert — auto-mocked
await Assert.That(serviceB).IsNotNull();
}
[Test]
public async Task Non_Interface_Return_Type_Returns_Default()
{
// Arrange
var mock = IServiceA.Mock();
// Act — GetName returns string, not an interface
var name = mock.Object.GetName();
// Assert — returns smart default (empty string)
await Assert.That(name).IsEqualTo("");
}
}