Skip to content

Commit c75545b

Browse files
authored
SentryMonoBehaviour Tests (#246)
1 parent 3afabd4 commit c75545b

File tree

8 files changed

+208
-13
lines changed

8 files changed

+208
-13
lines changed

src/Sentry.Unity/Integrations/IApplication.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ internal interface IApplication
1515
string Version { get; }
1616
string PersistentDataPath { get; }
1717
bool IsMainThread { get; }
18+
RuntimePlatform Platform { get; }
1819
}
1920

2021
internal sealed class ApplicationAdapter : IApplication
@@ -43,6 +44,8 @@ private ApplicationAdapter()
4344

4445
public bool IsMainThread => Thread.CurrentThread.ManagedThreadId == 1;
4546

47+
public RuntimePlatform Platform => Application.platform;
48+
4649
private void OnLogMessageReceived(string condition, string stackTrace, LogType type)
4750
=> LogMessageReceived?.Invoke(condition, stackTrace, type);
4851

src/Sentry.Unity/Integrations/SessionIntegration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ public void Register(IHub hub, SentryOptions options)
1616
options.DiagnosticLogger?.LogDebug("Registering Session integration.");
1717

1818
// HideFlags.HideAndDontSave hides the GameObject in the hierarchy and prevents changing of scenes from destroying it
19-
var gameListenerObject = new GameObject("SentryListener") {hideFlags = HideFlags.HideAndDontSave};
20-
var gameListener = gameListenerObject.AddComponent<ApplicationPauseListener>();
19+
var gameListenerObject = new GameObject("SentryMonoBehaviour") {hideFlags = HideFlags.HideAndDontSave};
20+
var gameListener = gameListenerObject.AddComponent<SentryMonoBehaviour>();
2121
gameListener.ApplicationResuming += () =>
2222
{
2323
options.DiagnosticLogger?.LogDebug("Resuming session.");

src/Sentry.Unity/ApplicationPauseListener.cs renamed to src/Sentry.Unity/SentryMonoBehaviour.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using Sentry.Unity.Integrations;
23
using UnityEngine;
34

45
namespace Sentry.Unity
@@ -7,7 +8,7 @@ namespace Sentry.Unity
78
/// A MonoBehavior used to forward application focus events to subscribers.
89
/// </summary>
910
[DefaultExecutionOrder(-900)]
10-
internal class ApplicationPauseListener : MonoBehaviour
11+
internal class SentryMonoBehaviour : MonoBehaviour
1112
{
1213
/// <summary>
1314
/// Hook to receive an event when the application gains focus.
@@ -28,6 +29,17 @@ internal class ApplicationPauseListener : MonoBehaviour
2829
// Keeping internal track of running state because OnApplicationPause and OnApplicationFocus get called during startup and would fire false resume events
2930
private bool _isRunning = true;
3031

32+
private IApplication? _application;
33+
internal IApplication Application
34+
{
35+
get
36+
{
37+
_application ??= ApplicationAdapter.Instance;
38+
return _application;
39+
}
40+
set => _application = value;
41+
}
42+
3143
/// <summary>
3244
/// To receive Leaving/Resuming events on Android.
3345
/// <remarks>
@@ -37,9 +49,9 @@ internal class ApplicationPauseListener : MonoBehaviour
3749
/// </remarks>
3850
/// <seealso href="https://docs.unity3d.com/2019.4/Documentation/ScriptReference/MonoBehaviour.OnApplicationPause.html"/>
3951
/// </summary>
40-
private void OnApplicationPause(bool pauseStatus)
52+
internal void OnApplicationPause(bool pauseStatus)
4153
{
42-
if (Application.platform != RuntimePlatform.Android)
54+
if (Application.Platform != RuntimePlatform.Android)
4355
{
4456
return;
4557
}
@@ -60,10 +72,10 @@ private void OnApplicationPause(bool pauseStatus)
6072
/// To receive Leaving/Resuming events on all platforms except Android.
6173
/// </summary>
6274
/// <param name="hasFocus"></param>
63-
private void OnApplicationFocus(bool hasFocus)
75+
internal void OnApplicationFocus(bool hasFocus)
6476
{
6577
// To avoid event duplication on Android since the pause event will be handled via OnApplicationPause
66-
if (Application.platform == RuntimePlatform.Android)
78+
if (Application.Platform == RuntimePlatform.Android)
6779
{
6880
return;
6981
}

src/Sentry.Unity/SentryOptionsUtility.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using Sentry.Unity.Integrations;
32

43
namespace Sentry.Unity

test/Sentry.Unity.Tests/IntegrationTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ public IEnumerator Init_OptionsAreDefaulted()
232232
UnitySentryOptionsTests.AssertOptions(expectedOptions, actualOptions!);
233233
}
234234

235-
private static IEnumerator SetupSceneCoroutine(string sceneName)
235+
internal static IEnumerator SetupSceneCoroutine(string sceneName)
236236
{
237237
// load scene with initialized Sentry, SceneManager.LoadSceneAsync(sceneName);
238238
SceneManager.LoadScene(sceneName);
@@ -244,11 +244,12 @@ private static IEnumerator SetupSceneCoroutine(string sceneName)
244244
LogAssert.ignoreFailingMessages = true;
245245
}
246246

247-
private static IDisposable InitSentrySdk(Action<SentryUnityOptions> configure)
247+
internal static IDisposable InitSentrySdk(Action<SentryUnityOptions> configure)
248248
{
249249
SentryUnity.Init(options =>
250250
{
251251
options.Dsn = "https://[email protected]/5439417";
252+
252253
configure.Invoke(options);
253254
});
254255
return new SentryDisposable();
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
using NUnit.Framework;
2+
using Sentry.Unity.Tests.Stubs;
3+
using UnityEngine;
4+
5+
namespace Sentry.Unity.Tests
6+
{
7+
public class SentryMonoBehaviourTests
8+
{
9+
private class Fixture
10+
{
11+
public SentryMonoBehaviour GetSut(RuntimePlatform platform)
12+
{
13+
var gameObject = new GameObject("PauseTest");
14+
var sentryMonoBehaviour = gameObject.AddComponent<SentryMonoBehaviour>();
15+
sentryMonoBehaviour.Application = new TestApplication(platform: platform);
16+
17+
return sentryMonoBehaviour;
18+
}
19+
}
20+
21+
private Fixture _fixture = null!;
22+
23+
[SetUp]
24+
public void SetUp()
25+
{
26+
_fixture = new Fixture();
27+
}
28+
29+
[Test]
30+
public void OnApplicationPause_OnAndroid_ApplicationPausingTriggered()
31+
{
32+
var wasPausingCalled = false;
33+
34+
var sut = _fixture.GetSut(RuntimePlatform.Android);
35+
sut.ApplicationPausing += () => wasPausingCalled = true;
36+
37+
sut.OnApplicationPause(true);
38+
39+
Assert.IsTrue(wasPausingCalled);
40+
}
41+
42+
[Test]
43+
public void OnApplicationPause_NotOnAndroid_ApplicationPausingNotTriggered()
44+
{
45+
var wasPausingCalled = false;
46+
47+
var sut = _fixture.GetSut(RuntimePlatform.IPhonePlayer);
48+
sut.ApplicationPausing += () => wasPausingCalled = true;
49+
50+
sut.OnApplicationPause(true);
51+
52+
Assert.IsFalse(wasPausingCalled);
53+
}
54+
55+
[Test]
56+
public void OnApplicationPause_OnAndroid_ApplicationPausingTriggeredOnlyOnce()
57+
{
58+
var pauseEventTriggerCounter = 0;
59+
60+
var sut = _fixture.GetSut(RuntimePlatform.Android);
61+
sut.ApplicationPausing += () => pauseEventTriggerCounter++;
62+
63+
sut.OnApplicationPause(true);
64+
sut.OnApplicationPause(true);
65+
66+
Assert.AreEqual(1, pauseEventTriggerCounter);
67+
}
68+
69+
[Test]
70+
public void OnApplicationPause_OnAndroid_PausingIsRequiredBeforeApplicationResumingTrigger()
71+
{
72+
var wasPausingCalled = false;
73+
var wasResumingCalled = false;
74+
75+
var sut = _fixture.GetSut(RuntimePlatform.Android);
76+
sut.ApplicationPausing += () => wasPausingCalled = true;
77+
sut.ApplicationResuming += () => wasResumingCalled = true;
78+
79+
sut.OnApplicationPause(false);
80+
81+
Assert.IsFalse(wasResumingCalled);
82+
83+
sut.OnApplicationPause(true);
84+
sut.OnApplicationPause(false);
85+
86+
Assert.IsTrue(wasPausingCalled);
87+
Assert.IsTrue(wasResumingCalled);
88+
}
89+
90+
[Test]
91+
public void OnApplicationFocus_OnAndroid_ApplicationPausingNotTriggered()
92+
{
93+
var wasPausingCalled = false;
94+
95+
var sut = _fixture.GetSut(RuntimePlatform.Android);
96+
sut.ApplicationPausing += () => wasPausingCalled = true;
97+
98+
sut.OnApplicationFocus(false);
99+
100+
Assert.IsFalse(wasPausingCalled);
101+
}
102+
103+
[Test]
104+
public void OnApplicationFocus_NotOnAndroid_ApplicationPausingTriggered()
105+
{
106+
var wasPausingCalled = false;
107+
108+
var sut = _fixture.GetSut(RuntimePlatform.IPhonePlayer);
109+
sut.ApplicationPausing += () => wasPausingCalled = true;
110+
111+
sut.OnApplicationFocus(false);
112+
113+
Assert.IsTrue(wasPausingCalled);
114+
}
115+
116+
[Test]
117+
public void OnApplicationFocus_NotOnAndroid_ApplicationPausingTriggeredOnlyOnce()
118+
{
119+
var pauseEventTriggerCounter = 0;
120+
121+
var sut = _fixture.GetSut(RuntimePlatform.IPhonePlayer);
122+
sut.ApplicationPausing += () => pauseEventTriggerCounter++;
123+
124+
sut.OnApplicationFocus(false);
125+
sut.OnApplicationFocus(false);
126+
127+
Assert.AreEqual(1, pauseEventTriggerCounter);
128+
}
129+
130+
[Test]
131+
public void OnApplicationFocus_NotOnAndroid_PausingIsRequiredBeforeApplicationResumingTrigger()
132+
{
133+
var wasPausingCalled = false;
134+
var wasResumingCalled = false;
135+
136+
var sut = _fixture.GetSut(RuntimePlatform.IPhonePlayer);
137+
sut.ApplicationPausing += () => wasPausingCalled = true;
138+
sut.ApplicationResuming += () => wasResumingCalled = true;
139+
140+
sut.OnApplicationFocus(true);
141+
142+
Assert.IsFalse(wasResumingCalled);
143+
144+
sut.OnApplicationFocus(false);
145+
sut.OnApplicationFocus(true);
146+
147+
Assert.IsTrue(wasPausingCalled);
148+
Assert.IsTrue(wasResumingCalled);
149+
}
150+
}
151+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Collections;
2+
using NUnit.Framework;
3+
using UnityEngine;
4+
using UnityEngine.TestTools;
5+
6+
namespace Sentry.Unity.Tests
7+
{
8+
public class SessionIntegrationTests
9+
{
10+
[UnityTest]
11+
public IEnumerator SessionIntegration_Init_SentryMonoBehaviourCreated()
12+
{
13+
yield return null;
14+
15+
using var _ = IntegrationTests.InitSentrySdk(o =>
16+
{
17+
// o.AutoSessionTracking = true; We expect this to be true by default
18+
});
19+
20+
var sentryGameObject = GameObject.Find("SentryMonoBehaviour");
21+
var sentryMonoBehaviour = sentryGameObject.GetComponent<SentryMonoBehaviour>();
22+
23+
Assert.IsNotNull(sentryGameObject);
24+
Assert.IsNotNull(sentryMonoBehaviour);
25+
}
26+
}
27+
}

test/Sentry.Unity.Tests/Stubs/TestApplication.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using Sentry.Unity.Integrations;
33
using UnityEngine;
4-
using UnityEngine.TestTools.Constraints;
54

65
namespace Sentry.Unity.Tests.Stubs
76
{
@@ -12,13 +11,16 @@ public TestApplication(
1211
string productName = "",
1312
string version = "",
1413
string persistentDataPath = "",
15-
bool isMainThread = true)
14+
bool isMainThread = true,
15+
RuntimePlatform platform = RuntimePlatform.WindowsEditor
16+
)
1617
{
1718
IsEditor = isEditor;
1819
ProductName = productName;
1920
Version = version;
2021
PersistentDataPath = persistentDataPath;
2122
IsMainThread = isMainThread;
23+
Platform = platform;
2224
}
2325

2426
public event Application.LogCallback? LogMessageReceived;
@@ -29,7 +31,7 @@ public TestApplication(
2931
public string Version { get; }
3032
public string PersistentDataPath { get; }
3133
public bool IsMainThread { get; }
32-
34+
public RuntimePlatform Platform { get; }
3335
private void OnQuitting() => Quitting?.Invoke();
3436

3537
private void OnLogMessageReceived(string condition, string stacktrace, LogType type)

0 commit comments

Comments
 (0)