{"componentChunkName":"component---src-templates-platform-tsx","path":"/platforms/dotnet/guides/extensions-logging/unit-testing/","result":{"data":{"file":{"id":"88ab5709-1ffa-5506-bfef-b514e1b6c2ac","relativePath":"dotnet/common/unit-testing.mdx","sourceInstanceName":"platforms","childMarkdownRemark":null,"childMdx":{"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"Unit Testing\"\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"We often don't want to couple our code with a static class like \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"SentrySdk\"), \". Especially to allow our code to be testable.\\nIf that's your case, you can use 2 abstractions:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"ISentryClient\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"IHub\"))), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ISentryClient\"), \" exposes the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"CaptureEvent\"), \" method and its implementation \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"SentryClient\"), \" is responsible for queueing the event to be sent to Sentry. It also abstracts away the internal transport.\"), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"IHub\"), \" on the other hand, holds a client and the current \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"../enriching-events/scopes/\"\n  }), \"scope\"), \". In fact, it extends \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ISentryClient\"), \" and is able to dispatch calls to the right client depending on the current scope.\"), mdx(\"p\", null, \"In order to allow different events to hold different contextual data, you need to know in which scope you are in.\\nThat's the job of the \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/getsentry/sentry-dotnet/blob/master/src/Sentry/Internal/Hub.cs\"\n  }), mdx(\"inlineCode\", {\n    parentName: \"a\"\n  }, \"Hub\")), \". It holds the scope management as well as a client.\"), mdx(\"p\", null, \"If all you are doing is sending events, without modification/access to the current scope, then you depend on \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ISentryClient\"), \". If on the other hand you would like to have access to the current scope by configuring it or binding a different client to it, you depend on \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"IHub\"), \".\"), mdx(\"p\", null, \"An example using \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"IHub\"), \" for testability is \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/getsentry/sentry-dotnet/blob/master/src/Sentry.Extensions.Logging/SentryLogger.cs\"\n  }), \"SentryLogger\"), \" and its unit tests \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/getsentry/sentry-dotnet/blob/master/test/Sentry.Extensions.Logging.Tests/SentryLoggerTests.cs\"\n  }), \"SentryLoggerTests\"), \".\\n\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"SentryLogger\"), \" depends on \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"IHub\"), \" because it does modify the scope (through \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"AddBreadcrumb\"), \"). In case it only sent events, it should instead depend on \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ISentryClient\")));\n}\n;\nMDXContent.isMDXComponent = true;","tableOfContents":{},"internal":{"type":"Mdx"}}}},"pageContext":{"excerpt":"We often don't want to couple our code with a static class like  SentrySdk . Especially to allow our code to be testable.\nIf that's your case, you can use 2 abstractions: ISentryClient IHub The  ISentryClient  exposes the  CaptureEvent  method and its implementation  SentryClient  is responsible for queueing the event to be sent to Sentry. It also abstracts away the internal transport. The  IHub  on the other hand, holds a client and the current  scope . In fact, it extends  ISentryClient  and is able to dispatch calls to the right client depending on the current scope. In order to allow different events to hold different contextual data, you need to know in which scope you are in.\nThat's the job of the  Hub . It holds the scope management as well as a client. If all you are doing is sending events, without modification/access to the current scope, then you depend on  ISentryClient . If on the other hand you would like to have access to the current scope by configuring it or binding a different client to it, you depend on  IHub . An example using  IHub  for testability is  SentryLogger  and its unit tests  SentryLoggerTests .\n SentryLogger  depends on  IHub  because it does modify the scope (through  AddBreadcrumb ). In case it only sent events, it should instead depend on  ISentryClient","title":"Unit Testing","platform":{"name":"dotnet","title":".NET"},"guide":{"name":"extensions-logging","title":"Microsoft.Extensions.Logging"},"noindex":true,"notoc":true,"redirect_from":[],"id":"88ab5709-1ffa-5506-bfef-b514e1b6c2ac"}},"staticQueryHashes":["1218203755","1222113826","1222113826","1766336459","2158593473","2404336828","2472290386","2764967025","3818502851","4015007367","4192517163","4264099332","518019976"]}