Skip to content

Commit 97b7f5c

Browse files
committed
feat(common): Add support to mock OptimizelyUserContext on unit tests
Supports mocking OptimizelyUserContext on frameworks as almost all of them require an interface.
1 parent 2af4a37 commit 97b7f5c

File tree

11 files changed

+144
-18
lines changed

11 files changed

+144
-18
lines changed

OptimizelySDK.Net35/OptimizelySDK.Net35.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@
148148
<Compile Include="..\OptimizelySDK\IOptimizely.cs">
149149
<Link>IOptimizely.cs</Link>
150150
</Compile>
151+
<Compile Include="..\OptimizelySDK\IOptimizelyUserContext.cs">
152+
<Link>IOptimizelyUserContext.cs</Link>
153+
</Compile>
151154
<Compile Include="..\OptimizelySDK\Logger\DefaultLogger.cs">
152155
<Link>Logger\DefaultLogger.cs</Link>
153156
</Compile>

OptimizelySDK.Net40/OptimizelySDK.Net40.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
</Reference>
4949
</ItemGroup>
5050
<ItemGroup>
51+
<Compile Include="..\OptimizelySDK\IOptimizelyUserContext.cs">
52+
<Link>IOptimizelyUserContext.cs</Link>
53+
</Compile>
5154
<Compile Include="..\OptimizelySDK\AudienceConditions\AndCondition.cs">
5255
<Link>AudienceConditions\AndCondition.cs</Link>
5356
</Compile>

OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@
100100
<Link>AtomicProjectConfigManager.cs</Link>
101101
</Compile>
102102
<Compile Include="..\OptimizelySDK\OptimizelyFactory.cs">
103-
<Link>OptimizelyFactory.cs</Link>
103+
<Link>OptimizelyFactory.cs</Link>
104+
</Compile>
105+
<Compile Include="..\OptimizelySDK\IOptimizelyUserContext.cs">
106+
<Link>IOptimizelyUserContext.cs</Link>
104107
</Compile>
105108
<Compile Include="..\OptimizelySDK\Event\Entity\ConversionEvent.cs">
106109
<Link>ConversionEvent.cs</Link>

OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
<Compile Include="..\OptimizelySDK\IOptimizely.cs">
1111
<Link>IOptimizely.cs</Link>
1212
</Compile>
13+
<Compile Include="..\OptimizelySDK\IOptimizelyUserContext.cs">
14+
<Link>IOptimizelyUserContext.cs</Link>
15+
</Compile>
1316
<Compile Include="..\OptimizelySDK\Optimizely.cs">
1417
<Link>Optimizely.cs</Link>
1518
</Compile>

OptimizelySDK.Tests/OptimizelyUserContextTest.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public void SetUp()
6363
public void OptimizelyUserContextWithAttributes()
6464
{
6565
var attributes = new UserAttributes() { { "house", "GRYFFINDOR" } };
66-
OptimizelyUserContext user = new OptimizelyUserContext(Optimizely, UserID, attributes, ErrorHandlerMock.Object, LoggerMock.Object);
66+
var user = new OptimizelyUserContext(Optimizely, UserID, attributes, ErrorHandlerMock.Object, LoggerMock.Object);
6767

6868
Assert.AreEqual(user.GetOptimizely(), Optimizely);
6969
Assert.AreEqual(user.GetUserId(), UserID);
@@ -73,7 +73,7 @@ public void OptimizelyUserContextWithAttributes()
7373
[Test]
7474
public void OptimizelyUserContextNoAttributes()
7575
{
76-
OptimizelyUserContext user = new OptimizelyUserContext(Optimizely, UserID, null, ErrorHandlerMock.Object, LoggerMock.Object);
76+
var user = new OptimizelyUserContext(Optimizely, UserID, null, ErrorHandlerMock.Object, LoggerMock.Object);
7777

7878
Assert.AreEqual(user.GetOptimizely(), Optimizely);
7979
Assert.AreEqual(user.GetUserId(), UserID);
@@ -84,7 +84,7 @@ public void OptimizelyUserContextNoAttributes()
8484
public void SetAttribute()
8585
{
8686
var attributes = new UserAttributes() { { "house", "GRYFFINDOR" } };
87-
OptimizelyUserContext user = new OptimizelyUserContext(Optimizely, UserID, attributes, ErrorHandlerMock.Object, LoggerMock.Object);
87+
var user = new OptimizelyUserContext(Optimizely, UserID, attributes, ErrorHandlerMock.Object, LoggerMock.Object);
8888

8989
user.SetAttribute("k1", "v1");
9090
user.SetAttribute("k2", true);
@@ -104,7 +104,7 @@ public void SetAttribute()
104104
[Test]
105105
public void SetAttributeNoAttribute()
106106
{
107-
OptimizelyUserContext user = new OptimizelyUserContext(Optimizely, UserID, null, ErrorHandlerMock.Object, LoggerMock.Object);
107+
var user = new OptimizelyUserContext(Optimizely, UserID, null, ErrorHandlerMock.Object, LoggerMock.Object);
108108

109109
user.SetAttribute("k1", "v1");
110110
user.SetAttribute("k2", true);
@@ -120,7 +120,7 @@ public void SetAttributeNoAttribute()
120120
public void SetAttributeOverride()
121121
{
122122
var attributes = new UserAttributes() { { "house", "GRYFFINDOR" } };
123-
OptimizelyUserContext user = new OptimizelyUserContext(Optimizely, UserID, attributes, ErrorHandlerMock.Object, LoggerMock.Object);
123+
var user = new OptimizelyUserContext(Optimizely, UserID, attributes, ErrorHandlerMock.Object, LoggerMock.Object);
124124

125125
user.SetAttribute("k1", "v1");
126126
user.SetAttribute("house", "v2");
@@ -134,7 +134,7 @@ public void SetAttributeOverride()
134134
public void SetAttributeNullValue()
135135
{
136136
var attributes = new UserAttributes() { { "k1", null } };
137-
OptimizelyUserContext user = new OptimizelyUserContext(Optimizely, UserID, attributes, ErrorHandlerMock.Object, LoggerMock.Object);
137+
var user = new OptimizelyUserContext(Optimizely, UserID, attributes, ErrorHandlerMock.Object, LoggerMock.Object);
138138

139139
var newAttributes = user.GetAttributes();
140140
Assert.AreEqual(newAttributes["k1"], null);
@@ -151,7 +151,7 @@ public void SetAttributeNullValue()
151151
[Test]
152152
public void SetAttributeToOverrideAttribute()
153153
{
154-
OptimizelyUserContext user = new OptimizelyUserContext(Optimizely, UserID, null, ErrorHandlerMock.Object, LoggerMock.Object);
154+
var user = new OptimizelyUserContext(Optimizely, UserID, null, ErrorHandlerMock.Object, LoggerMock.Object);
155155

156156

157157
Assert.AreEqual(user.GetOptimizely(), Optimizely);

OptimizelySDK/IOptimizely.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public interface IOptimizely
4141
/// <param name="userId">The user ID to be used for bucketing.</param>
4242
/// <param name="userAttributes">The user's attributes</param>
4343
/// <returns>OptimizelyUserContext | An OptimizelyUserContext associated with this OptimizelyClient.</returns>
44-
OptimizelyUserContext CreateUserContext(string userId, UserAttributes userAttributes = null);
44+
IOptimizelyUserContext CreateUserContext(string userId, UserAttributes userAttributes = null);
4545

4646
/// <summary>
4747
/// Sends conversion event to Optimizely.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright 2020-2021, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
using OptimizelySDK.Entity;
18+
using OptimizelySDK.OptimizelyDecisions;
19+
using System.Collections.Generic;
20+
21+
namespace OptimizelySDK
22+
{
23+
public interface IOptimizelyUserContext
24+
{
25+
/// <summary>
26+
/// Returns a decision result ({@link OptimizelyDecision}) for a given flag key and a user context, which contains all data required to deliver the flag.
27+
/// <ul>
28+
/// <li>If the SDK finds an error, it’ll return a decision with <b>null</b> for <b>variationKey</b>. The decision will include an error message in <b>reasons</b>.
29+
/// </ul>
30+
/// </summary>
31+
/// <param name="key">A flag key for which a decision will be made.</param>
32+
/// <returns>A decision result.</returns>
33+
OptimizelyDecision Decide(string key);
34+
35+
/// <summary>
36+
/// Returns a decision result ({@link OptimizelyDecision}) for a given flag key and a user context, which contains all data required to deliver the flag.
37+
/// <ul>
38+
/// <li>If the SDK finds an error, it’ll return a decision with <b>null</b> for <b>variationKey</b>. The decision will include an error message in <b>reasons</b>.
39+
/// </ul>
40+
/// </summary>
41+
/// <param name="key">A flag key for which a decision will be made.</param>
42+
/// <param name="options">A list of options for decision-making.</param>
43+
/// <returns>A decision result.</returns>
44+
OptimizelyDecision Decide(string key, OptimizelyDecideOption[] options);
45+
46+
/// <summary>
47+
/// Returns a key-map of decision results ({@link OptimizelyDecision}) for all active flag keys.
48+
/// </summary>
49+
/// <returns>A dictionary of all decision results, mapped by flag keys.</returns>
50+
Dictionary<string, OptimizelyDecision> DecideAll();
51+
52+
/// <summary>
53+
/// Returns a key-map of decision results ({@link OptimizelyDecision}) for all active flag keys.
54+
/// </summary>
55+
/// <param name="options">A list of options for decision-making.</param>
56+
/// <returns>All decision results mapped by flag keys.</returns>
57+
Dictionary<string, OptimizelyDecision> DecideAll(OptimizelyDecideOption[] options);
58+
59+
/// <summary>
60+
/// Returns a key-map of decision results for multiple flag keys and a user context.
61+
/// </summary>
62+
/// <param name="keys">list of flag keys for which a decision will be made.</param>
63+
/// <returns>A dictionary of all decision results, mapped by flag keys.</returns>
64+
Dictionary<string, OptimizelyDecision> DecideForKeys(string[] keys);
65+
66+
/// <summary>
67+
/// Returns a key-map of decision results for multiple flag keys and a user context.
68+
/// </summary>
69+
/// <param name="keys">list of flag keys for which a decision will be made.</param>
70+
/// <param name="options">An array of decision options.</param>
71+
/// <returns></returns>
72+
Dictionary<string, OptimizelyDecision> DecideForKeys(string[] keys, OptimizelyDecideOption[] options);
73+
74+
/// <summary>
75+
/// Returns copy of UserAttributes associated with UserContext.
76+
/// </summary>
77+
/// <returns>copy of UserAttributes.</returns>
78+
UserAttributes GetAttributes();
79+
80+
/// <summary>
81+
/// Returns Optimizely instance associated with the UserContext.
82+
/// </summary>
83+
/// <returns> Optimizely instance.</returns>
84+
Optimizely GetOptimizely();
85+
86+
/// <summary>
87+
/// Returns UserId associated with the UserContext
88+
/// </summary>
89+
/// <returns>UserId of this instance.</returns>
90+
string GetUserId();
91+
92+
/// <summary>
93+
/// Set an attribute for a given key.
94+
/// </summary>
95+
/// <param name="key">An attribute key</param>
96+
/// <param name="value">value An attribute value</param>
97+
void SetAttribute(string key, object value);
98+
99+
/// <summary>
100+
/// Track an event.
101+
/// </summary>
102+
/// <param name="eventName">The event name.</param>
103+
void TrackEvent(string eventName);
104+
105+
/// <summary>
106+
/// Track an event.
107+
/// </summary>
108+
/// <param name="eventName">The event name.</param>
109+
/// <param name="eventTags">A map of event tag names to event tag values.</param>
110+
void TrackEvent(string eventName, EventTags eventTags);
111+
}
112+
}

OptimizelySDK/Optimizely.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ public OptimizelyJSON GetFeatureVariableJSON(string featureKey, string variableK
700700
/// <param name="userId">The user ID to be used for bucketing.</param>
701701
/// <param name="userAttributes">The user's attributes</param>
702702
/// <returns>OptimizelyUserContext | An OptimizelyUserContext associated with this OptimizelyClient.</returns>
703-
public OptimizelyUserContext CreateUserContext(string userId,
703+
public IOptimizelyUserContext CreateUserContext(string userId,
704704
UserAttributes userAttributes = null)
705705
{
706706
var inputValues = new Dictionary<string, string>
@@ -724,7 +724,7 @@ public OptimizelyUserContext CreateUserContext(string userId,
724724
/// <param name="key">A flag key for which a decision will be made.</param>
725725
/// <param name="options">A list of options for decision-making.</param>
726726
/// <returns>A decision result.</returns>
727-
internal OptimizelyDecision Decide(OptimizelyUserContext user,
727+
internal OptimizelyDecision Decide(IOptimizelyUserContext user,
728728
string key,
729729
OptimizelyDecideOption[] options)
730730
{
@@ -844,7 +844,7 @@ internal OptimizelyDecision Decide(OptimizelyUserContext user,
844844
reasonsToReport);
845845
}
846846

847-
internal Dictionary<string, OptimizelyDecision> DecideAll(OptimizelyUserContext user,
847+
internal Dictionary<string, OptimizelyDecision> DecideAll(IOptimizelyUserContext user,
848848
OptimizelyDecideOption[] options)
849849
{
850850
var decisionMap = new Dictionary<string, OptimizelyDecision>();
@@ -862,7 +862,7 @@ internal Dictionary<string, OptimizelyDecision> DecideAll(OptimizelyUserContext
862862
return DecideForKeys(user, allFlagKeys, options);
863863
}
864864

865-
internal Dictionary<string, OptimizelyDecision> DecideForKeys(OptimizelyUserContext user,
865+
internal Dictionary<string, OptimizelyDecision> DecideForKeys(IOptimizelyUserContext user,
866866
string[] keys,
867867
OptimizelyDecideOption[] options)
868868
{

OptimizelySDK/OptimizelyDecisions/OptimizelyDecision.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class OptimizelyDecision
5353
/// <summary>
5454
/// user context for which the decision was made.
5555
/// </summary>
56-
public OptimizelyUserContext UserContext { get; private set; }
56+
public IOptimizelyUserContext UserContext { get; private set; }
5757

5858
/// <summary>
5959
/// an array of error/info/debug messages describing why the decision has been made.
@@ -65,7 +65,7 @@ public OptimizelyDecision(string variationKey,
6565
OptimizelyJSON variables,
6666
string ruleKey,
6767
string flagKey,
68-
OptimizelyUserContext userContext,
68+
IOptimizelyUserContext userContext,
6969
string[] reasons)
7070
{
7171
VariationKey = variationKey;
@@ -84,7 +84,7 @@ public OptimizelyDecision(string variationKey,
8484
/// and error reason array
8585
/// </summary>
8686
public static OptimizelyDecision NewErrorDecision(string key,
87-
OptimizelyUserContext optimizelyUserContext,
87+
IOptimizelyUserContext optimizelyUserContext,
8888
string error,
8989
IErrorHandler errorHandler,
9090
ILogger logger)

OptimizelySDK/OptimizelySDK.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
<Compile Include="Entity\Group.cs" />
8888
<Compile Include="Entity\IdKeyEntity.cs" />
8989
<Compile Include="Event\Entity\DecisionMetadata.cs" />
90+
<Compile Include="IOptimizelyUserContext.cs" />
9091
<Compile Include="OptimizelyDecisions\DecisionMessage.cs" />
9192
<Compile Include="OptimizelyDecisions\DecisionReasons.cs" />
9293
<Compile Include="OptimizelyDecisions\OptimizelyDecideOption.cs" />

0 commit comments

Comments
 (0)